1 | initial version |
Please visit the following link :
https://www.pastiebin.com/5d0da17bccc9a
I have snippet of code which can help you to find the largest contour area of rectangle.
2 | No.2 Revision |
Please visit the following link :
https://www.pastiebin.com/5d0da17bccc9a
I have snippet of code which can help you to find the largest contour area of rectangle.
protected Bitmap findEdges(Bitmap rotatedBitmap) {
Mat rgba = new Mat();
Utils.bitmapToMat(rotatedBitmap, rgba);
Mat edges = new Mat(rgba.size(), CV_8UC1);
Imgproc.cvtColor(rgba, edges, Imgproc.COLOR_RGB2GRAY, 4);
Canny(edges, edges, 80, 100);
Bitmap resultBitmap = Bitmap.createBitmap(edges.cols(), edges.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(edges, resultBitmap);
// https://github.com/daisygao/ScannerLites
Mat rgbMat = new Mat();
Mat grayMat = new Mat();
Mat cannyMat;
Mat linesMat = new Mat();
BitmapFactory.Options o = new BitmapFactory.Options();
// define the destination image size: A4 - 200 PPI
int w_a4 = 1654, h_a4 = 2339;
// TODO: 29/08/2016 May need to check sample size https://developer.android.com/training/displaying-bitmaps/load-bitmap.html
o.inSampleSize = 4;
o.inDither = false;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
rotatedBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
try {
// resize
rotatedBitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
} catch (OutOfMemoryError error) {
error.printStackTrace();
}
int w = rotatedBitmap.getWidth();
int h = rotatedBitmap.getHeight();
int min_w = 800;
double scale = Math.min(10.0, w * 1.0 / min_w);
int w_proc = (int)(w * 1.0 / scale);
int h_proc = (int)(h * 1.0 / scale);
Bitmap srcBitmap = Bitmap.createScaledBitmap(rotatedBitmap, w_proc, h_proc, false);
Utils.bitmapToMat(srcBitmap, rgbMat); //convert original bitmap to Mat, R G B.
// grayscale
Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY); //rgbMat to gray grayMat
// canny
cannyMat = getCanny(grayMat);
// HoughLinesP
Imgproc.HoughLinesP(cannyMat, linesMat, 1, Math.PI / 280, w_proc / 12, w_proc / 12, 20);
// Calculate horizontal lines and vertical lines
Log.e("opencv", "lines.cols " + linesMat.cols() + " w_proc/3: " + w_proc / 3);
List < Line > horizontals = new ArrayList < > ();
List < Line > verticals = new ArrayList < > ();
for (int x = 0; x < linesMat.rows(); x++) {
double[] vec = linesMat.get(x, 0);
double x1 = vec[0],
y1 = vec[1],
x2 = vec[2],
y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
Line line = new Line(start, end);
if (Math.abs(x1 - x2) > Math.abs(y1 - y2)) {
horizontals.add(line);
} else {
verticals.add(line);
}
// for visualization in debug mode
if (BuildConfig.DEBUG) {}
}
Log.e("HoughLines", "completed HoughLines");
Log.e("HoughLines", "linesMat size: " + linesMat.size());
Log.e("Lines Detected", Integer.toString(linesMat.rows()));
// if we don't have at least 2 horizontal lines or vertical lines
if (horizontals.size() < 2) {
if (horizontals.size() == 0 || horizontals.get(0)._center.y > h_proc / 2) {
horizontals.add(new Line(new Point(0, 0), new Point(w_proc - 1, 0)));
}
if (horizontals.size() == 0 || horizontals.get(0)._center.y <= h_proc / 2) {
horizontals.add(new Line(new Point(0, h_proc - 1), new Point(w_proc - 1, h_proc - 1)));
}
}
if (verticals.size() < 2) {
if (verticals.size() == 0 || verticals.get(0)._center.x > w_proc / 2) {
verticals.add(new Line(new Point(0, 0), new Point(h_proc - 1, 0)));
}
if (verticals.size() == 0 || verticals.get(0)._center.x <= w_proc / 2) {
verticals.add(new Line(new Point(w_proc - 1, 0), new Point(w_proc - 1, h_proc - 1)));
}
}
Collections.sort(horizontals, new Comparator < Line > () {
@Override
public int compare(Line lhs, Line rhs) {
return (int)(lhs._center.y - rhs._center.y);
}
});
Collections.sort(verticals, new Comparator < Line > () {
@Override
public int compare(Line lhs, Line rhs) {
return (int)(lhs._center.x - rhs._center.x);
}
});
// for visualization in debug mode
if (BuildConfig.DEBUG) {}
// compute intersections
List < Point > intersections = new ArrayList < > ();
intersections.add(computeIntersection(horizontals.get(0), verticals.get(0)));
intersections.add(computeIntersection(horizontals.get(0), verticals.get(verticals.size() - 1)));
intersections.add(computeIntersection(horizontals.get(horizontals.size() - 1), verticals.get(0)));
intersections.add(computeIntersection(horizontals.get(horizontals.size() - 1), verticals.get(verticals.size() - 1)));
Log.e("Intersections", Double.toString(intersections.get(0).x));
for (Point point: intersections) {
// for visualization in debug mode
if (BuildConfig.DEBUG) {}
}
Log.e("Intersections", Double.toString(intersections.get(0).x));
// perspective transform
// Calculate max width and height
double w1 = Math.sqrt(Math.pow(intersections.get(3).x - intersections.get(2).x, 2) + Math.pow(intersections.get(3).x - intersections.get(2).x, 2));
double w2 = Math.sqrt(Math.pow(intersections.get(1).x - intersections.get(0).x, 2) + Math.pow(intersections.get(1).x - intersections.get(0).x, 2));
double h1 = Math.sqrt(Math.pow(intersections.get(1).y - intersections.get(3).y, 2) + Math.pow(intersections.get(1).y - intersections.get(3).y, 2));
double h2 = Math.sqrt(Math.pow(intersections.get(0).y - intersections.get(2).y, 2) + Math.pow(intersections.get(0).y - intersections.get(2).y, 2));
double maxWidth = (w1 < w2) ? w1 : w2;
double maxHeight = (h1 < h2) ? h1 : h2;
// source Mat from earlier intersection calculations
Mat srcMat = new Mat(4, 1, CvType.CV_32FC2);
srcMat.put(0, 0, intersections.get(0).x, intersections.get(0).y, intersections.get(1).x, intersections.get(1).y, intersections.get(2).x, intersections.get(2).y, intersections.get(3).x, intersections.get(3).y);
Mat dstMat = new Mat(4, 1, CvType.CV_32FC2);
dstMat.put(0, 0, 0.0, 0.0, maxWidth - 1, 0.0, 0.0, maxHeight - 1, maxWidth - 1, maxHeight - 1);
Log.e("FinalDisplay", "srcMat: " + srcMat.size());
Log.e("FinalDisplay", "dstMat: " + dstMat.size());
// transformation matrix
Mat transformMatrix = Imgproc.getPerspectiveTransform(srcMat, dstMat);
Mat finalMat = Mat.zeros((int) maxHeight, (int) maxWidth, CV_8UC1);
Imgproc.warpPerspective(rgbMat, finalMat, transformMatrix, finalMat.size());
Log.e("FinalDisplay", "finalMat: " + finalMat.size());
// display final results
Bitmap dstBitmap = Bitmap.createBitmap(finalMat.width(), finalMat.height(), Bitmap.Config.RGB_565);
Log.e("FinalDisplay", "dstBitmap: " + dstBitmap.getWidth() + " x " + dstBitmap.getHeight());
Utils.matToBitmap(finalMat, dstBitmap); //convert mat to bitmap
return dstBitmap;
}
public double calculateDistanceBetweenPoints(
double x1,
double y1,
double x2,
double y2) {
return Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
}
protected Mat getCanny(Mat gray) {
Mat canny = new Mat();
// last paramter 8 is using OTSU algorithm
double high_threshold = 255; //threshold(gray, threshold,240, 200, 8);
double low_threshold = high_threshold * 0.5;
Canny(gray, canny, low_threshold - 20, high_threshold * 2.5);
// display final results
Bitmap dstBitmap = Bitmap.createBitmap(canny.width(), canny.height(), Bitmap.Config.RGB_565);
Utils.matToBitmap(canny, dstBitmap); //convert mat to bitmap
return canny;
}
protected Point computeIntersection(Line l1, Line l2) {
double x1 = l1._p1.x, x2 = l1._p2.x, y1 = l1._p1.y, y2 = l1._p2.y;
double x3 = l2._p1.x, x4 = l2._p2.x, y3 = l2._p1.y, y4 = l2._p2.y;
double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
Point pt = new Point();
pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
return pt;
}
class Line {
Point _p1;
Point _p2;
Point _center;
Line(Point p1, Point p2) {
_p1 = p1;
_p2 = p2;
_center = new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
}
}
3 | No.3 Revision |
Please visit the following link :
I have snippet of code which can help you to find the largest contour area of rectangle.
protected Bitmap findEdges(Bitmap rotatedBitmap) {
Mat rgba = new Mat();
Utils.bitmapToMat(rotatedBitmap, rgba);
Mat edges = new Mat(rgba.size(), CV_8UC1);
Imgproc.cvtColor(rgba, edges, Imgproc.COLOR_RGB2GRAY, 4);
Canny(edges, edges, 80, 100);
Bitmap resultBitmap = Bitmap.createBitmap(edges.cols(), edges.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(edges, resultBitmap);
// https://github.com/daisygao/ScannerLites
Mat rgbMat = new Mat();
Mat grayMat = new Mat();
Mat cannyMat;
Mat linesMat = new Mat();
BitmapFactory.Options o = new BitmapFactory.Options();
// define the destination image size: A4 - 200 PPI
int w_a4 = 1654, h_a4 = 2339;
// TODO: 29/08/2016 May need to check sample size https://developer.android.com/training/displaying-bitmaps/load-bitmap.html
o.inSampleSize = 4;
o.inDither = false;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
rotatedBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
try {
// resize
rotatedBitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
} catch (OutOfMemoryError error) {
error.printStackTrace();
}
int w = rotatedBitmap.getWidth();
int h = rotatedBitmap.getHeight();
int min_w = 800;
double scale = Math.min(10.0, w * 1.0 / min_w);
int w_proc = (int)(w * 1.0 / scale);
int h_proc = (int)(h * 1.0 / scale);
Bitmap srcBitmap = Bitmap.createScaledBitmap(rotatedBitmap, w_proc, h_proc, false);
Utils.bitmapToMat(srcBitmap, rgbMat); //convert original bitmap to Mat, R G B.
// grayscale
Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY); //rgbMat to gray grayMat
// canny
cannyMat = getCanny(grayMat);
// HoughLinesP
Imgproc.HoughLinesP(cannyMat, linesMat, 1, Math.PI / 280, w_proc / 12, w_proc / 12, 20);
// Calculate horizontal lines and vertical lines
Log.e("opencv", "lines.cols " + linesMat.cols() + " w_proc/3: " + w_proc / 3);
List < Line > horizontals = new ArrayList < > ();
List < Line > verticals = new ArrayList < > ();
for (int x = 0; x < linesMat.rows(); x++) {
double[] vec = linesMat.get(x, 0);
double x1 = vec[0],
y1 = vec[1],
x2 = vec[2],
y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
Line line = new Line(start, end);
if (Math.abs(x1 - x2) > Math.abs(y1 - y2)) {
horizontals.add(line);
} else {
verticals.add(line);
}
// for visualization in debug mode
if (BuildConfig.DEBUG) {}
}
Log.e("HoughLines", "completed HoughLines");
Log.e("HoughLines", "linesMat size: " + linesMat.size());
Log.e("Lines Detected", Integer.toString(linesMat.rows()));
// if we don't have at least 2 horizontal lines or vertical lines
if (horizontals.size() < 2) {
if (horizontals.size() == 0 || horizontals.get(0)._center.y > h_proc / 2) {
horizontals.add(new Line(new Point(0, 0), new Point(w_proc - 1, 0)));
}
if (horizontals.size() == 0 || horizontals.get(0)._center.y <= h_proc / 2) {
horizontals.add(new Line(new Point(0, h_proc - 1), new Point(w_proc - 1, h_proc - 1)));
}
}
if (verticals.size() < 2) {
if (verticals.size() == 0 || verticals.get(0)._center.x > w_proc / 2) {
verticals.add(new Line(new Point(0, 0), new Point(h_proc - 1, 0)));
}
if (verticals.size() == 0 || verticals.get(0)._center.x <= w_proc / 2) {
verticals.add(new Line(new Point(w_proc - 1, 0), new Point(w_proc - 1, h_proc - 1)));
}
}
Collections.sort(horizontals, new Comparator < Line > () {
@Override
public int compare(Line lhs, Line rhs) {
return (int)(lhs._center.y - rhs._center.y);
}
});
Collections.sort(verticals, new Comparator < Line > () {
@Override
public int compare(Line lhs, Line rhs) {
return (int)(lhs._center.x - rhs._center.x);
}
});
// for visualization in debug mode
if (BuildConfig.DEBUG) {}
// compute intersections
List < Point > intersections = new ArrayList < > ();
intersections.add(computeIntersection(horizontals.get(0), verticals.get(0)));
intersections.add(computeIntersection(horizontals.get(0), verticals.get(verticals.size() - 1)));
intersections.add(computeIntersection(horizontals.get(horizontals.size() - 1), verticals.get(0)));
intersections.add(computeIntersection(horizontals.get(horizontals.size() - 1), verticals.get(verticals.size() - 1)));
Log.e("Intersections", Double.toString(intersections.get(0).x));
for (Point point: intersections) {
// for visualization in debug mode
if (BuildConfig.DEBUG) {}
}
Log.e("Intersections", Double.toString(intersections.get(0).x));
// perspective transform
// Calculate max width and height
double w1 = Math.sqrt(Math.pow(intersections.get(3).x - intersections.get(2).x, 2) + Math.pow(intersections.get(3).x - intersections.get(2).x, 2));
double w2 = Math.sqrt(Math.pow(intersections.get(1).x - intersections.get(0).x, 2) + Math.pow(intersections.get(1).x - intersections.get(0).x, 2));
double h1 = Math.sqrt(Math.pow(intersections.get(1).y - intersections.get(3).y, 2) + Math.pow(intersections.get(1).y - intersections.get(3).y, 2));
double h2 = Math.sqrt(Math.pow(intersections.get(0).y - intersections.get(2).y, 2) + Math.pow(intersections.get(0).y - intersections.get(2).y, 2));
double maxWidth = (w1 < w2) ? w1 : w2;
double maxHeight = (h1 < h2) ? h1 : h2;
// source Mat from earlier intersection calculations
Mat srcMat = new Mat(4, 1, CvType.CV_32FC2);
srcMat.put(0, 0, intersections.get(0).x, intersections.get(0).y, intersections.get(1).x, intersections.get(1).y, intersections.get(2).x, intersections.get(2).y, intersections.get(3).x, intersections.get(3).y);
Mat dstMat = new Mat(4, 1, CvType.CV_32FC2);
dstMat.put(0, 0, 0.0, 0.0, maxWidth - 1, 0.0, 0.0, maxHeight - 1, maxWidth - 1, maxHeight - 1);
Log.e("FinalDisplay", "srcMat: " + srcMat.size());
Log.e("FinalDisplay", "dstMat: " + dstMat.size());
// transformation matrix
Mat transformMatrix = Imgproc.getPerspectiveTransform(srcMat, dstMat);
Mat finalMat = Mat.zeros((int) maxHeight, (int) maxWidth, CV_8UC1);
Imgproc.warpPerspective(rgbMat, finalMat, transformMatrix, finalMat.size());
Log.e("FinalDisplay", "finalMat: " + finalMat.size());
// display final results
Bitmap dstBitmap = Bitmap.createBitmap(finalMat.width(), finalMat.height(), Bitmap.Config.RGB_565);
Log.e("FinalDisplay", "dstBitmap: " + dstBitmap.getWidth() + " x " + dstBitmap.getHeight());
Utils.matToBitmap(finalMat, dstBitmap); //convert mat to bitmap
return dstBitmap;
}
public double calculateDistanceBetweenPoints(
double x1,
double y1,
double x2,
double y2) {
return Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
}
protected Mat getCanny(Mat gray) {
Mat canny = new Mat();
// last paramter 8 is using OTSU algorithm
double high_threshold = 255; //threshold(gray, threshold,240, 200, 8);
double low_threshold = high_threshold * 0.5;
1.5;
Canny(gray, canny, low_threshold - 20, high_threshold * 2.5);
// display final results
Bitmap dstBitmap = Bitmap.createBitmap(canny.width(), canny.height(), Bitmap.Config.RGB_565);
Utils.matToBitmap(canny, dstBitmap); //convert mat to bitmap
return canny;
}
protected Point computeIntersection(Line l1, Line l2) {
double x1 = l1._p1.x, x2 = l1._p2.x, y1 = l1._p1.y, y2 = l1._p2.y;
double x3 = l2._p1.x, x4 = l2._p2.x, y3 = l2._p1.y, y4 = l2._p2.y;
double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
Point pt = new Point();
pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
return pt;
}
class Line {
Point _p1;
Point _p2;
Point _center;
Line(Point p1, Point p2) {
_p1 = p1;
_p2 = p2;
_center = new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
}
}