-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScanLayer.cpp
More file actions
122 lines (99 loc) · 3.82 KB
/
ScanLayer.cpp
File metadata and controls
122 lines (99 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
Mat imggryblr, imgcanny, imgdilate, imgwarp;
Mat preprocessing(Mat img) {
cvtColor(img, imggryblr, COLOR_BGR2GRAY);
GaussianBlur(imggryblr, imggryblr, Size(3, 3), 3, 0);
Canny(imggryblr, imgcanny, 50, 150);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(imgcanny, imgdilate, kernel);
return imgdilate;
}
vector<Point> getContours(Mat img, Mat &imgDraw) {
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
vector<Point> biggest;
int maxArea = 0;
findContours(img, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++) {
float area = contourArea(contours[i]);
if (area > 1000) {
vector<Point> approx;
float peri = arcLength(contours[i], true);
approxPolyDP(contours[i], approx, 0.02 * peri, true);
if (approx.size() == 4) {
Rect bound = boundingRect(approx);
float aspectRatio = (float)bound.width / bound.height;
if (area > maxArea && aspectRatio > 0.6 && aspectRatio < 1.5) {
biggest = approx;
maxArea = area;
}
}
}
}
// Draw the biggest contour for visual debug
if (!biggest.empty()) {
vector<vector<Point>> drawBiggest{biggest};
drawContours(imgDraw, drawBiggest, -1, Scalar(255, 0, 255), 3);
}
return biggest;
}
vector<Point> reorderPoints(vector<Point> points) {
vector<Point> newPoints(4);
vector<int> sumPts, diffPts;
for (int i = 0; i < 4; i++) {
sumPts.push_back(points[i].x + points[i].y);
diffPts.push_back(points[i].y - points[i].x);
}
newPoints[0] = points[min_element(sumPts.begin(), sumPts.end()) - sumPts.begin()]; // Top-left
newPoints[3] = points[max_element(sumPts.begin(), sumPts.end()) - sumPts.begin()]; // Bottom-right
newPoints[1] = points[min_element(diffPts.begin(), diffPts.end()) - diffPts.begin()]; // Top-right
newPoints[2] = points[max_element(diffPts.begin(), diffPts.end()) - diffPts.begin()]; // Bottom-left
return newPoints;
}
void findXY(vector<Point> points, float &w, float &h) {
float widthTop = norm(points[1] - points[0]);
float widthBottom = norm(points[3] - points[2]);
w = max(widthTop, widthBottom);
float heightLeft = norm(points[2] - points[0]);
float heightRight = norm(points[3] - points[1]);
h = max(heightLeft, heightRight);
}
Mat getWarp(Mat img, vector<Point> points, float w, float h) {
Point2f src[4] = {points[0], points[1], points[2], points[3]};
Point2f dst[4] = {{0.0f, 0.0f}, {w, 0.0f}, {0.0f, h}, {w, h}};
Mat matrix = getPerspectiveTransform(src, dst);
warpPerspective(img, imgwarp, matrix, Size(w, h));
return imgwarp;
}
int main() {
string path = "E:/OpenCVResources/imgdoc.jpg";
Mat imgOriginal = imread(path);
if (imgOriginal.empty()) {
cout << "Image not found!" << endl;
return -1;
}
Mat imgDraw = imgOriginal.clone();
Mat imgThres = preprocessing(imgOriginal);
vector<Point> docPoints = getContours(imgThres, imgDraw);
if (docPoints.empty()) {
cout << "No document detected!" << endl;
return -1;
}
docPoints = reorderPoints(docPoints);
float width, height;
findXY(docPoints, width, height);
Mat warped = getWarp(imgOriginal, docPoints, width, height);
// Optional cropping to remove white edges
int cropVal = 5;
Rect roi(cropVal, cropVal, width - 2 * cropVal, height - 2 * cropVal);
Mat cropped = warped(roi);
// Show results
imshow("Original Image", imgDraw);
imshow("Scanned Image", cropped);
imwrite("E:/OpenCVResources/imgcrop.jpg", cropped);
waitKey(0);
return 0;
}