I need create an app for Document Detect Edges on Cameraframe . In Coloured Background it Not Detected Edges Correclty .Contour drawn are Collapsed.Please suggestion
I does not Give expected Result.
try {
return findLargestRectangle(inputFrame.rgba());
} catch (Exception e) {
e.printStackTrace();
}
private Mat findLargestRectangle(Mat original_image) {
Mat imgSource = original_image;
//Mat untouched = original_image.clone();
//Clone the Image
Mat CloneImage =original_image.clone();
//convert the image to black and white
Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY);
//convert the image to black and white does (8 bit)
Imgproc.Canny(imgSource, imgSource, 50, 50);
//apply gaussian blur to smoothen lines of dots
Imgproc.GaussianBlur(imgSource, imgSource, new Size(5, 5), 5);
//find the contours
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(imgSource, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double maxArea = -1;
int maxAreaIdx = -1;
MatOfPoint temp_contour = contours.get(0); //the largest is at the index 0 for starting point
MatOfPoint2f approxCurve = new MatOfPoint2f();
MatOfPoint2f maxCurve = new MatOfPoint2f();
List<MatOfPoint> largest_contours = new ArrayList<MatOfPoint>();
for (int idx = 0; idx < contours.size(); idx++) {
temp_contour = contours.get(idx);
double contourarea = Imgproc.contourArea(temp_contour);
//compare this contour to the previous largest contour found
if (contourarea > maxArea) {
//check if this contour is a square
MatOfPoint2f new_mat = new MatOfPoint2f( temp_contour.toArray() );
int contourSize = (int)temp_contour.total();
Imgproc.approxPolyDP(new_mat, approxCurve, contourSize*0.05, true);
if (approxCurve.total() == 4) {
maxCurve = approxCurve;
maxArea = contourarea;
maxAreaIdx = idx;
largest_contours.add(temp_contour);
}
}
}
Scalar GREEN = new Scalar(0,255,0);
// Imgproc.drawContours(CloneImage, contours, maxAreaIdx, new Scalar(255, 255, 255), 1); //will draw the largest square/rectangle
// Attempt to draw a GREEN box, but it comes out white
Imgproc.line(CloneImage, new Point(maxCurve.get(3, 0)), new Point(maxCurve.get(2, 0)), GREEN, 4);
Imgproc.line(CloneImage, new Point(maxCurve.get(2, 0)), new Point(maxCurve.get(1, 0)), GREEN, 4);
Imgproc.line(CloneImage, new Point(maxCurve.get(1, 0)), new Point(maxCurve.get(0, 0)), GREEN, 4);
Imgproc.line(CloneImage, new Point(maxCurve.get(0, 0)), new Point(maxCurve.get(3, 0)), GREEN, 4);
double temp_double[] = maxCurve.get(0, 0);
Point p1 = new Point(temp_double[0], temp_double[1]);
Imgproc.circle(CloneImage, new Point(p1.x, p1.y), 20, new Scalar(255, 0, 0), 5); //p1 is colored red
String temp_string = "Point 1: (" + p1.x + ", " + p1.y + ")";
temp_double = maxCurve.get(1, 0);
Point p2 = new Point(temp_double[0], temp_double[1]);
Imgproc.circle(CloneImage, new Point(p2.x, p2.y), 20, new Scalar(0, 255, 0), 5); //p2 is colored green
temp_string += "\nPoint 2: (" + p2.x + ", " + p2.y + ")";
temp_double = maxCurve.get(2, 0);
Point p3 = new Point(temp_double[0], temp_double[1]);
Imgproc.circle(CloneImage, new Point(p3.x, p3.y), 20, new Scalar(0, 0, 255), 5); //p3 is colored blue
temp_string += "\nPoint 3: (" + p3.x + ", " + p3.y + ")";
temp_double = maxCurve.get(3, 0);
Point p4 = new Point(temp_double[0], temp_double[1]);
// if(Imgproc.contourArea(contours.get(contourIdx))>100) {
Imgproc.circle(CloneImage, new Point(p4.x, p4.y), 20, new Scalar(0, 255, 255), 5); //p4 is colored violet
// }
temp_string += "\nPoint 4: (" + p4.x + ", " + p4.y + ")";
/* if(isCapture) {
Rect roi = new Rect(40, 100, 100, 120);
Mat cropped = new Mat(CloneImage, roi);
Bitmap bmp = Bitmap.createBitmap(200, 400, Bitmap.Config.ARGB_8888);
Mat tmp = new Mat (200,200,CvType.CV_8UC1,new Scalar(4));
try {
//Imgproc.cvtColor(seedsImage, tmp, Imgproc.COLOR_RGB2BGRA);
Imgproc.cvtColor(cropped, tmp, Imgproc.COLOR_GRAY2RGBA, 4);
Utils.matToBitmap(tmp, bmp);
img_capture.setImageBitmap(bmp);
}
catch (CvException e){Log.d("Exception",e.getMessage());}*/
//}
return CloneImage;
}
My question
1.Detection Document Edge On Background an Different Algorithm ?
2.Please suggestion give suggestion or tutorial for edged edection?
my Ouptup of the Image
https://drive.google.com/open?id=1oZZ2A4T2TdMcIKzJ5mrg_qR5yX71dGd5
Related
public class Grabcut extends Activity {
ImageView iv;
Bitmap bitmap;
Canvas canvas;
Scalar color = new Scalar(255, 0, 0, 255);
Point tl, br;
int counter;
Bitmap bitmapResult, bitmapBackground;
Mat dst = new Mat();
final String pathToImage = Environment.getExternalStorageDirectory()+"/gcut.png";
public static final String TAG = "Grabcut demo";
static {
if (!OpenCVLoader.initDebug()) {
// Handle initialization error
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.grabcut_main);
iv = (ImageView) this.findViewById(R.id.imageView);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.grabcut);
Log.d(TAG, "bitmap: " + bitmap.getWidth() + "x" + bitmap.getHeight());
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Log.d(TAG, "bitmap 8888: " + bitmap.getWidth() + "x" + bitmap.getHeight());
//GrabCut part
Mat img = new Mat();
Utils.bitmapToMat(bitmap, img);
Log.d(TAG, "img: " + img);
int r = img.rows();
int c = img.cols();
Point p1 = new Point(c/5, r/5);
Point p2 = new Point(c-c/5, r-r/8);
Rect rect = new Rect(p1,p2);
//Rect rect = new Rect(50,30, 100,200);
Log.d(TAG, "rect: " + rect);
Mat mask = new Mat();
debugger(""+mask.type());
mask.setTo(new Scalar(125));
Mat fgdModel = new Mat();
fgdModel.setTo(new Scalar(255, 255, 255));
Mat bgdModel = new Mat();
bgdModel.setTo(new Scalar(255, 255, 255));
Mat imgC3 = new Mat();
Imgproc.cvtColor(img, imgC3, Imgproc.COLOR_RGBA2RGB);
Log.d(TAG, "imgC3: " + imgC3);
Log.d(TAG, "Grabcut begins");
Imgproc.grabCut(imgC3, mask, rect, bgdModel, fgdModel, 5, Imgproc.GC_INIT_WITH_RECT);
Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(3.0));
Core.compare(mask, source, mask, Core.CMP_EQ);
Mat foreground = new Mat(img.size(), CvType.CV_8UC3, new Scalar(255, 255, 255));
img.copyTo(foreground, mask);
Core.rectangle(img, p1, p2, color);
Mat background = new Mat();
try {
background = Utils.loadResource(getApplicationContext(),
R.drawable.wall2 );
} catch (IOException e) {
e.printStackTrace();
}
Mat tmp = new Mat();
Imgproc.resize(background, tmp, img.size());
background = tmp;
Mat tempMask = new Mat(foreground.size(), CvType.CV_8UC1, new Scalar(255, 255, 255));
Imgproc.cvtColor(foreground, tempMask, 6/* COLOR_BGR2GRAY */);
//Imgproc.threshold(tempMask, tempMask, 254, 255, 1 /* THRESH_BINARY_INV */);
Mat vals = new Mat(1, 1, CvType.CV_8UC3, new Scalar(0.0));
dst = new Mat();
background.setTo(vals, tempMask);
Imgproc.resize(foreground, tmp, mask.size());
foreground = tmp;
Core.add(background, foreground, dst, tempMask);
//convert to Bitmap
Log.d(TAG, "Convert to Bitmap");
Utils.matToBitmap(dst, bitmap);
iv.setBackgroundResource(R.drawable.wall2);
iv.setImageBitmap(bitmap);
//release MAT part
img.release();
imgC3.release();
mask.release();
fgdModel.release();
bgdModel.release();
}
public void debugger(String s){
Log.v("","########### "+s);
}
}
I had followed above tutorial.But problem is that output image I get has brighter colors than my input image. Why is that and how to solve it?
My input image is Here and output image is here.Output image is actually screenshot of my application where large one is input image and small one with black background is output image.
I finally found solution to my problem. Here is code to grab cut background of an image using Grabcut algorithm in opencv for android.
public void grabcutAlgo(Bitmap bit){
Bitmap b = bit.copy(Bitmap.Config.ARGB_8888, true);
Point tl=new Point();
Point br=new Point();
//GrabCut part
Mat img = new Mat();
Utils.bitmapToMat(b, img);
Imgproc.cvtColor(img, img, Imgproc.COLOR_RGBA2RGB);
int r = img.rows();
int c = img.cols();
Point p1 = new Point(c / 100, r / 100);
Point p2 = new Point(c - c / 100, r - r / 100);
Rect rect = new Rect(p1, p2);
//Rect rect = new Rect(tl, br);
Mat background = new Mat(img.size(), CvType.CV_8UC3,
new Scalar(255, 255, 255));
Mat firstMask = new Mat();
Mat bgModel = new Mat();
Mat fgModel = new Mat();
Mat mask;
Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(Imgproc.GC_PR_FGD));
Mat dst = new Mat();
Imgproc.grabCut(img, firstMask, rect, bgModel, fgModel, 5, Imgproc.GC_INIT_WITH_RECT);
Core.compare(firstMask, source, firstMask, Core.CMP_EQ);
Mat foreground = new Mat(img.size(), CvType.CV_8UC3, new Scalar(255, 255, 255));
img.copyTo(foreground, firstMask);
Scalar color = new Scalar(255, 0, 0, 255);
Imgproc.rectangle(img, tl, br, color);
Mat tmp = new Mat();
Imgproc.resize(background, tmp, img.size());
background = tmp;
mask = new Mat(foreground.size(), CvType.CV_8UC1,
new Scalar(255, 255, 255));
Imgproc.cvtColor(foreground, mask, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(mask, mask, 254, 255, Imgproc.THRESH_BINARY_INV);
System.out.println();
Mat vals = new Mat(1, 1, CvType.CV_8UC3, new Scalar(0.0));
background.copyTo(dst);
background.setTo(vals, mask);
Core.add(background, foreground, dst, mask);
Bitmap grabCutImage = Bitmap.createBitmap(dst.cols(), dst.rows(), Bitmap.Config.ARGB_8888);
Bitmap processedImage = Bitmap.createBitmap(dst.cols(), dst.rows(), Bitmap.Config.RGB_565);
Utils.matToBitmap(dst, grabCutImage);
dst.copyTo(sampleImage);
imageView.setImageBitmap(grabCutImage);
firstMask.release();
source.release();
bgModel.release();
fgModel.release();
}
I am trying to use this code http://androiderstuffs.blogspot.com/2016/06/detecting-rectangle-using-opencv-java.html to detect card. But instead of putting card on plane surface, I will be holding this card in hand in-front of my Head. Problem is, its not detecting card rectangle. I am new to OpenCV. See my code below, this code will highlight all found rectangles in output image. Problem is, it never find card rectangle.
private void findRectangleOpen(Bitmap image) throws Exception {
Mat tempor = new Mat();
Mat src = new Mat();
Utils.bitmapToMat(image, tempor);
Imgproc.cvtColor(tempor, src, Imgproc.COLOR_BGR2RGB);
Mat blurred = src.clone();
Imgproc.medianBlur(src, blurred, 9);
Mat gray0 = new Mat(blurred.size(), CvType.CV_8U), gray = new Mat();
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<Mat> blurredChannel = new ArrayList<Mat>();
blurredChannel.add(blurred);
List<Mat> gray0Channel = new ArrayList<Mat>();
gray0Channel.add(gray0);
MatOfPoint2f approxCurve;
int maxId = -1;
for (int c = 0; c < 3; c++) {
int ch[] = {c, 0};
Core.mixChannels(blurredChannel, gray0Channel, new MatOfInt(ch));
int thresholdLevel = 1;
for (int t = 0; t < thresholdLevel; t++) {
if (t == 0) {
Imgproc.Canny(gray0, gray, 10, 20, 3, true); // true ?
Imgproc.dilate(gray, gray, new Mat(), new Point(-1, -1), 1); // 1
// ?
} else {
Imgproc.adaptiveThreshold(gray0, gray, thresholdLevel,
Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
Imgproc.THRESH_BINARY,
(src.width() + src.height()) / 200, t);
}
Imgproc.findContours(gray, contours, new Mat(),
Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
int i = 0;
for (MatOfPoint contour : contours) {
MatOfPoint2f temp = new MatOfPoint2f(contour.toArray());
double area = Imgproc.contourArea(contour);
approxCurve = new MatOfPoint2f();
Imgproc.approxPolyDP(temp, approxCurve,
Imgproc.arcLength(temp, true) * 0.02, true);
if (approxCurve.total() == 4 && area >= 200 && area <= 40000) {
double maxCosine = 0;
List<Point> curves = approxCurve.toList();
for (int j = 2; j < 5; j++) {
double cosine = Math.abs(angle(curves.get(j % 4),
curves.get(j - 2), curves.get(j - 1)));
maxCosine = Math.max(maxCosine, cosine);
}
if (maxCosine < 0.3) {
Imgproc.drawContours(src, contours, i, new Scalar(255, 0, 0), 3);
Bitmap bmp;
bmp = Bitmap.createBitmap(src.cols(), src.rows(),
Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, bmp);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
//File origFile = getFileForSaving();
savePhoto(byteArray);
bmp.recycle();
}
}
i++;
}
}
}
}
private static double angle(org.opencv.core.Point p1, org.opencv.core.Point p2, org.opencv.core.Point p0) {
double dx1 = p1.x - p0.x;
double dy1 = p1.y - p0.y;
double dx2 = p2.x - p0.x;
double dy2 = p2.y - p0.y;
return (dx1 * dx2 + dy1 * dy2)
/ sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2)
+ 1e-10);
}
Sample output image is:
Output of detecting rectangle
I am very new to android and openCV, I'M working on "Android application: plant disease Analyzer".
Below is my workflow:
1.I have static plant diseases in my gallery
2.End-user can capture an plant disease and submit to my application.
3.I want to compare the processed image with my gallery(Diseases) to get the most similar disease
Can any one tell me What will be the best algorithm to use?,
I have been searching on google but no luck,I tried with
below code snippet, which I tried using openCV :
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
Bitmap camerabitmap = BitmapFactory.decodeFile(cameraimage,
bmOptions);
Bitmap galareybitmap =
BitmapFactory.decodeFile(galImage.getAbsolutePath(), bmOptions);
private double imageProcessing(Bitmap cameraimage,Bitmap
galimagebitmap,String galimagename) throws IOException {
Mat img1 = new Mat();
Utils.bitmapToMat(cameraimage, img1);
Mat img2 = new Mat();
Utils.bitmapToMat(gallimagebitmap, img2);
Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGBA2GRAY);
Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGBA2GRAY);
img1.convertTo(img1, CvType.CV_32F);
img2.convertTo(img2, CvType.CV_32F);
//Log.d("ImageComparator", "img1:"+img1.rows()+"x"+img1.cols()+" img2:"+img2.rows()+"x"+img2.cols());
Mat hist1 = new Mat();
Mat hist2 = new Mat();
MatOfInt histSize = new MatOfInt(180);
MatOfInt channels = new MatOfInt(0);
ArrayList<Mat> bgr_planes1= new ArrayList<Mat>();
ArrayList<Mat> bgr_planes2= new ArrayList<Mat>();
Core.split(img1, bgr_planes1);
Core.split(img2, bgr_planes2);
MatOfFloat histRanges = new MatOfFloat(0f, 256f);
boolean accumulate = false;
Imgproc.calcHist(bgr_planes1, channels, new Mat(), hist1, histSize, histRanges);
Core.normalize(hist1, hist1, 0, hist1.rows(), Core.NORM_MINMAX, -1, new Mat());
Imgproc.calcHist(bgr_planes2, channels, new Mat(), hist2, histSize, histRanges);
Core.normalize(hist2, hist2, 0, hist2.rows(), Core.NORM_MINMAX, -1, new Mat());
/ img1.convertTo(img1, CvType.CV_32F);
// img2.convertTo(img2, CvType.CV_32F);
hist1.convertTo(hist1, CvType.CV_32F);
hist2.convertTo(hist2, CvType.CV_32F);
return Imgproc.compareHist(hist1, hist2,3);
}
I tried with template matching also in opencv
int match_method=Imgproc.TM_CCOEFF_NORMED;
Mat temp = Imgcodecs.imread(tempim,Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE );
Mat img = Imgcodecs.imread(sourceim,Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE
);
Size sz = new Size(200, 200);
Mat resizeimage = new Mat();
Imgproc.resize(img, resizeimage, sz);
Mat sourceimage = resizeimage;
Mat resizeimage2 = new Mat();
Imgproc.resize(temp, resizeimage2, sz);
Mat templateimage = resizeimage2;
int result_cols = sourceimage.cols() - templateimage.cols() + 1;
int result_rows = sourceimage.rows() - templateimage.rows() + 1;
Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);
Imgproc.matchTemplate(sourceimage,templateimage, result, match_method);
//Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
Imgproc.threshold(result, result,0.1,1,Imgproc.THRESH_TOZERO);
Point matchLoc,maxLoc,minLoc;
Core.MinMaxLocResult mmr;
boolean iterate = true;
double minlocvalue,maxlocvalue,minminvalue,maxmaxvalue;
while(true){
mmr = Core.minMaxLoc(result);
if (match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED) {
matchLoc = mmr.minLoc;
minminvalue = mmr.minVal; // test
} else {
matchLoc = mmr.maxLoc;
maxmaxvalue = mmr.minVal; // test
}
Log.d(TAG, "mmr.maxVal : "+mmr.maxVal);
if(mmr.maxVal >=0.2)
{
Log.d(TAG, "imagemathed..");
Imgproc.rectangle(sourceimage, matchLoc, new Point(matchLoc.x + templateimage.cols(),
matchLoc.y + templateimage.rows()), new Scalar(0, 255, 0));
Imgcodecs.imwrite(outFile, img);
Mat image = Imgcodecs.imread(outFile);
try {
Bitmap bm = Bitmap.createBitmap(image.cols(), image.rows(), Bitmap.Config.RGB_565);
Utils.matToBitmap(image, bm);
System.out.println("MinVal "+bm);
}catch(Exception e){
e.printStackTrace();
}
return true;
}else {
Log.d(TAG, "image not mathced..");
return false;
}
}
But every time I'M not getting the proper output, fault images are coming in the output.Please help me out, AM I following right approach, If not can some one suggest me which approach i have to follow.
I can detect largest contour the answer sheet (20 questions, each have 4 alternative)
After the draw largest contour, what shall I do? Divide matris the rectangle by 20x4 cell? Or find countour again but this time inside the rectangle? I dont know what I need. Just I want to get which is marked.
I looked at this documant.
How to codding "image gridding and division"?
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
return findLargestRectangle(inputFrame.rgba());
}
private Mat findLargestRectangle(Mat original_image) {
Mat imgSource = original_image;
hierarchy = new Mat();
//convert the image to black and white
Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY);
//convert the image to black and white does (8 bit)
Imgproc.Canny(imgSource, imgSource, 50, 50);
//apply gaussian blur to smoothen lines of dots
Imgproc.GaussianBlur(imgSource, imgSource, new Size(5, 5), 5);
//find the contours
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(imgSource, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
hierarchy.release();
double maxArea = -1;
int maxAreaIdx = -1;
MatOfPoint temp_contour = contours.get(0); //the largest is at the index 0 for starting point
MatOfPoint2f approxCurve = new MatOfPoint2f();
Mat largest_contour = contours.get(0);
List<MatOfPoint> largest_contours = new ArrayList<MatOfPoint>();
for (int idx = 0; idx < contours.size(); idx++) {
temp_contour = contours.get(idx);
double contourarea = Imgproc.contourArea(temp_contour);
//compare this contour to the previous largest contour found
if (contourarea > maxArea) {
//check if this contour is a square
MatOfPoint2f new_mat = new MatOfPoint2f( temp_contour.toArray() );
int contourSize = (int)temp_contour.total();
Imgproc.approxPolyDP(new_mat, approxCurve, contourSize*0.05, true);
if (approxCurve.total() == 4) {
maxArea = contourarea;
maxAreaIdx = idx;
largest_contours.add(temp_contour);
largest_contour = temp_contour;
}
}
}
MatOfPoint temp_largest = largest_contours.get(largest_contours.size()-1);
largest_contours = new ArrayList<MatOfPoint>();
largest_contours.add(temp_largest);
Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BayerBG2RGB);
Imgproc.drawContours(imgSource, contours, maxAreaIdx, new Scalar(0, 255, 0), 1);
Log.d(TAG, "Largers Contour:" + contours.get(maxAreaIdx).toString());
return imgSource;
}
UPDATE 1:
I want to thank you #sturkmen for the his answer. I can read and find black regions now. Here the Android codes:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View _view = inflater.inflate(R.layout.fragment_main, container, false);
// Inflate the layout for this fragment
Button btnTest = (Button) _view.findViewById(R.id.btnTest);
btnTest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Mat img = Imgcodecs.imread(mediaStorageDir().getPath() + "/" + "test2.jpg");
if (img.empty()) {
Log.d("Fragment", "IMG EMPTY");
}
Mat gray = new Mat();
Mat thresh = new Mat();
//convert the image to black and white
Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY);
//convert the image to black and white does (8 bit)
Imgproc.threshold(gray, thresh, 0, 255, Imgproc.THRESH_BINARY_INV + Imgproc.THRESH_OTSU);
Mat temp = thresh.clone();
//find the contours
Mat hierarchy = new Mat();
Mat corners = new Mat(4,1, CvType.CV_32FC2);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(temp, contours,hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
hierarchy.release();
for (int idx = 0; idx < contours.size(); idx++)
{
MatOfPoint contour = contours.get(idx);
MatOfPoint2f contour_points = new MatOfPoint2f(contour.toArray());
RotatedRect minRect = Imgproc.minAreaRect( contour_points );
Point[] rect_points = new Point[4];
minRect.points( rect_points );
if(minRect.size.height > img.width() / 2)
{
List<Point> srcPoints = new ArrayList<Point>(4);
srcPoints.add(rect_points[2]);
srcPoints.add(rect_points[3]);
srcPoints.add(rect_points[0]);
srcPoints.add(rect_points[1]);
corners = Converters.vector_Point_to_Mat(
srcPoints, CvType.CV_32F);
}
}
Imgproc.erode(thresh, thresh, new Mat(), new Point(-1,-1), 10);
Imgproc.dilate(thresh, thresh, new Mat(), new Point(-1,-1), 5);
Mat results = new Mat(1000,250,CvType.CV_8UC3);
Mat quad = new Mat(1000,250,CvType.CV_8UC1);
List<Point> dstPoints = new ArrayList<Point>(4);
dstPoints.add(new Point(0, 0));
dstPoints.add(new Point(1000, 0));
dstPoints.add(new Point(1000, 250));
dstPoints.add(new Point(0, 250));
Mat quad_pts = Converters.vector_Point_to_Mat(
dstPoints, CvType.CV_32F);
Mat transmtx = Imgproc.getPerspectiveTransform(corners, quad_pts);
Imgproc.warpPerspective( img, results, transmtx, new Size(1000,250));
Imgproc.warpPerspective( thresh, quad, transmtx, new Size(1000,250));
Imgproc.resize(quad,quad,new Size(20,5));
Imgcodecs.imwrite("results.png",quad);
//show image
showImage(quad);
//store image
storeImage(quad);
}
});
return _view;
}
public void showImage (Mat img) {
ImageView imgView = (ImageView) getActivity().findViewById(R.id.sampleImageView);
//Mat mRgba = new Mat();
//mRgba = Utils.loadResource(MainAct.this, R.drawable.your_image,Highgui.CV_LOAD_IMAGE_COLOR);
Bitmap img2 = Bitmap.createBitmap(img.cols(), img.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(img, img2);
imgView.setImageBitmap(img2);
}
public File mediaStorageDir () {
File _mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ getActivity().getApplicationContext().getPackageName());
return _mediaStorageDir;
}
public void storeImage(Mat matImg) {
Bitmap bitmapImg = Bitmap.createBitmap(matImg.cols(), matImg.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(matImg, bitmapImg);
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
File mediaFile;
String mImageName="IMG_"+ timeStamp +".jpg";
mediaFile = new File(mediaStorageDir().getPath() + File.separator + mImageName);
File pictureFile = mediaFile;
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
bitmapImg.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.close();
} catch (FileNotFoundException e) {
Log.d("FragmentMain", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("FragmentMain", "Error accessing file: " + e.getMessage());
}
}
here is my trial code as a sample.
i hope it will be helpful. ( i will add some explanation about the code later)
Test Image ( edited your image. having an empty and invalid double mark )
(source: opencv.org)
Result Image
(source: opencv.org)
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
int main( int argc, const char** argv )
{
Mat img = imread(argv[1]);
if(img.empty())
{
return -1;
}
Size dims(20,5); // this variable should be changed according input
Mat gray,thresh;
cvtColor(img, gray, COLOR_BGR2GRAY);
threshold(gray, thresh, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
Mat quad(img.size(), CV_8UC1); // should be improved
Mat results(img.size(), CV_8UC3);
vector<Point2f> quad_pts;
quad_pts.push_back(cv::Point2f(0, 0));
quad_pts.push_back(cv::Point2f(quad.cols, 0));
quad_pts.push_back(cv::Point2f(quad.cols, quad.rows));
quad_pts.push_back(cv::Point2f(0, quad.rows));
vector<Point2f> corners;
vector<vector<Point> > contours;
findContours(thresh.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for( size_t i = 0; i< contours.size(); i++ )
{
RotatedRect minRect = minAreaRect( Mat(contours[i]) );
// rotated rectangle
Point2f rect_points[4];
minRect.points( rect_points );
if(Rect(minRect.boundingRect()).width > img.cols / 2) // should be improved
for( int j = 0; j < 4; j++ )
{
Point2f pt = quad_pts[j];
Point2f nearest_pt = rect_points[0];
float dist = norm( pt - nearest_pt );
for( int k = 1; k < 4; k++ )
{
if( norm( pt - rect_points[k] ) < dist )
{
dist = norm( pt - rect_points[k] );
nearest_pt = rect_points[k];
}
}
corners.push_back( nearest_pt );
}
}
erode(thresh,thresh,Mat(),Point(-1,-1), 10); // should be improved
dilate(thresh,thresh,Mat(),Point(-1,-1), 5); // should be improved
Mat transmtx = getPerspectiveTransform(corners, quad_pts);
warpPerspective( img, results, transmtx, img.size()); // Create a Mat To Show results
warpPerspective( thresh, quad, transmtx, img.size());
resize(quad,quad,dims);
for(int i = 0; i < quad.cols; i++)
{
String answer = "";
answer += quad.at<uchar>(1,i) == 0 ? "" : "A";
answer += quad.at<uchar>(2,i) == 0 ? "" : "B";
answer += quad.at<uchar>(3,i) == 0 ? "" : "C";
answer += quad.at<uchar>(4,i) == 0 ? "" : "D";
if( answer.length() > 1 ) answer = "X"; // Double mark
int y = 0;
if( answer == "A" ) y = results.rows / dims.height;
if( answer == "B" ) y = results.rows / dims.height *2;
if( answer == "C" ) y = results.rows / dims.height *3;
if( answer == "D" ) y = results.rows / dims.height *4;
if( answer == "" ) answer = "[-]";
putText( results, answer, Point( 50* i + 15, 30 + y), FONT_HERSHEY_PLAIN, 2, Scalar(0,0,255),2);
}
imshow( "results", results );
waitKey(0);
return 0;
}
as a challenge to myself i tried to implement main part in JAVA ( a newcomer copy paste code )
Mat img = Imgcodecs.imread("test.jpg");
Mat gray = new Mat();
Mat thresh = new Mat();
//convert the image to black and white
Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY);
//convert the image to black and white does (8 bit)
Imgproc.threshold(gray, thresh, 0, 255, Imgproc.THRESH_BINARY_INV + Imgproc.THRESH_OTSU);
Mat temp = thresh.clone();
//find the contours
Mat hierarchy = new Mat();
Mat corners = new Mat(4,1,CvType.CV_32FC2);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(temp, contours,hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
hierarchy.release();
for (int idx = 0; idx < contours.size(); idx++)
{
MatOfPoint contour = contours.get(idx);
MatOfPoint2f contour_points = new MatOfPoint2f(contour.toArray());
RotatedRect minRect = Imgproc.minAreaRect( contour_points );
Point[] rect_points = new Point[4];
minRect.points( rect_points );
if(minRect.size.height > img.width() / 2)
{
List<Point> srcPoints = new ArrayList<Point>(4);
srcPoints.add(rect_points[2]);
srcPoints.add(rect_points[3]);
srcPoints.add(rect_points[0]);
srcPoints.add(rect_points[1]);
corners = Converters.vector_Point_to_Mat(
srcPoints, CvType.CV_32F);
}
}
Imgproc.erode(thresh, thresh, new Mat(), new Point(-1,-1), 10);
Imgproc.dilate(thresh, thresh, new Mat(), new Point(-1,-1), 5);
Mat results = new Mat(1000,250,CvType.CV_8UC3);
Mat quad = new Mat(1000,250,CvType.CV_8UC1);
List<Point> dstPoints = new ArrayList<Point>(4);
dstPoints.add(new Point(0, 0));
dstPoints.add(new Point(1000, 0));
dstPoints.add(new Point(1000, 250));
dstPoints.add(new Point(0, 250));
Mat quad_pts = Converters.vector_Point_to_Mat(
dstPoints, CvType.CV_32F);
Mat transmtx = Imgproc.getPerspectiveTransform(corners, quad_pts);
Imgproc.warpPerspective( img, results, transmtx, new Size(1000,250));
Imgproc.warpPerspective( thresh, quad, transmtx, new Size(1000,250));
Imgproc.resize(quad,quad,new Size(20,5));
Imgcodecs.imwrite("results.png",quad);
here is the (20x5px) result image :
I imrove #sturkmen' s code.
fragment_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="{your package name}.FragmentMain">
<!-- TODO: Update blank fragment layout -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btnTest"
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="Test" />
<ImageView
android:id="#+id/sampleImageView"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_centerHorizontal="true"/>
</LinearLayout>
</framelayout>
AndroidManifest.xml
Add this line for write permission.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
FragmentMain.java
IMAGE FILE: Add Internal Storage/Android/Data/Your Package Folder/test.JPG
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View _view = inflater.inflate(R.layout.fragment_main, container, false);
Button btnTest = (Button) _view.findViewById(R.id.btnTest);
btnTest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Mat img = Imgcodecs.imread(mediaStorageDir().getPath() + "/" + "test.JPG");
if (img.empty()) {
Log.d("FragmentMain", "Empty Image");
}
Size dims = new Size (20,5);
Mat gray = new Mat();
Mat thresh = new Mat();
//convert the image to black and white
Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY);
storeImage(gray);
//convert the image to black and white does (8 bit)
Imgproc.threshold(gray, thresh, 0, 255, Imgproc.THRESH_BINARY_INV + Imgproc.THRESH_OTSU);
storeImage(thresh);
Mat temp = thresh.clone();
//find the contours
Mat hierarchy = new Mat();
Mat corners = new Mat(4,1, CvType.CV_32FC2);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(temp, contours,hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
hierarchy.release();
for (int idx = 0; idx < contours.size(); idx++)
{
MatOfPoint contour = contours.get(idx);
MatOfPoint2f contour_points = new MatOfPoint2f(contour.toArray());
RotatedRect minRect = Imgproc.minAreaRect( contour_points );
Point[] rect_points = new Point[4];
minRect.points( rect_points );
if(minRect.size.height > img.width() / 2)
{
List<Point> srcPoints = new ArrayList<Point>(4);
srcPoints.add(rect_points[2]);
srcPoints.add(rect_points[3]);
srcPoints.add(rect_points[0]);
srcPoints.add(rect_points[1]);
corners = Converters.vector_Point_to_Mat(
srcPoints, CvType.CV_32F);
}
}
Imgproc.erode(thresh, thresh, new Mat(), new Point(-1,-1), 10);
storeImage(thresh);
Imgproc.dilate(thresh, thresh, new Mat(), new Point(-1,-1), 5);
storeImage(thresh);
Mat results = new Mat(1000,250,CvType.CV_8UC3);
Mat quad = new Mat(1000,250,CvType.CV_8UC1);
List<Point> dstPoints = new ArrayList<Point>(4);
dstPoints.add(new Point(0, 0));
dstPoints.add(new Point(1000, 0));
dstPoints.add(new Point(1000, 250));
dstPoints.add(new Point(0, 250));
Mat quad_pts = Converters.vector_Point_to_Mat(
dstPoints, CvType.CV_32F);
Mat transmtx = Imgproc.getPerspectiveTransform(corners, quad_pts);
Imgproc.warpPerspective( img, results, transmtx, new Size(1000,250));
Imgproc.warpPerspective( thresh, quad, transmtx, new Size(1000,250));
Imgproc.resize(quad, quad, new Size(20,5));
Imgcodecs.imwrite("results.png",quad);
//store image
storeImage(quad);
//show image
showImage(quad);
System.out.println( quad.dump() );
for(int i = 0; i < quad.cols(); i++)
{
int size = (int) (quad.total() * quad.channels());
byte[] tmp = new byte[size];
String answer = "";
double[] d = new double[0];
d = quad.get(1, i);
answer += d[0] == 0 ? "" : "A";
d = quad.get(2, i);
answer += d[0] == 0 ? "" : "B";
d = quad.get(3, i);
answer += d[0] == 0 ? "" : "C";
d = quad.get(4, i);
answer += d[0] == 0 ? "" : "D";
if( answer.length() > 1 ) answer = "X"; // Double mark
int y = 0;
if( answer.equals("A")) y = results.rows() / (int) dims.height;
if( answer.equals("B")) y = results.rows() / (int) dims.height *2;
if( answer.equals("C")) y = results.rows() / (int) dims.height *3;
if( answer.equals("D")) y = results.rows() / (int) dims.height *4;
if( answer == "" ) answer = "[-]";
Imgproc.putText( results, answer, new Point( 50* i + 15, 30 + y), Core.FONT_HERSHEY_PLAIN, 2, new Scalar(0,0,255),2);
}
//store image
storeImage(results);
//show image
showImage(results);
}
});
public void showImage (Mat img) {
ImageView imgView = (ImageView) getActivity().findViewById(R.id.sampleImageView);
//Mat mRgba = new Mat();
//mRgba = Utils.loadResource(MainAct.this, R.drawable.your_image,Highgui.CV_LOAD_IMAGE_COLOR);
Bitmap img2 = Bitmap.createBitmap(img.cols(), img.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(img, img2);
imgView.setImageBitmap(img2);
}
public File mediaStorageDir () {
File _mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ getActivity().getApplicationContext().getPackageName());
return _mediaStorageDir;
}
public void storeImage(Mat matImg) {
Bitmap bitmapImg = Bitmap.createBitmap(matImg.cols(), matImg.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(matImg, bitmapImg);
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
File mediaFile;
String mImageName="IMG_"+ timeStamp +".jpg";
mediaFile = new File(mediaStorageDir().getPath() + File.separator + mImageName);
File pictureFile = mediaFile;
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
bitmapImg.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.close();
} catch (FileNotFoundException e) {
Log.d("FragmentMain", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("FragmentMain", "Error accessing file: " + e.getMessage());
}
}
In Ios we can:
Is there a way to detect if an image is blurry?
I don't know how to detect image is blur or not in Android or Java?
private void opencvProcess() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = true;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap image = decodeSampledBitmapFromFile(picFilePath, options, 2000, 2000);
int l = CvType.CV_8UC1; //8-bit grey scale image
Mat matImage = new Mat();
Utils.bitmapToMat(image, matImage);
Mat matImageGrey = new Mat();
Imgproc.cvtColor(matImage, matImageGrey, Imgproc.COLOR_BGR2GRAY);
Bitmap destImage;
destImage = Bitmap.createBitmap(image);
Mat dst2 = new Mat();
Utils.bitmapToMat(destImage, dst2);
Mat laplacianImage = new Mat();
dst2.convertTo(laplacianImage, l);
Imgproc.Laplacian(matImageGrey, laplacianImage, CvType.CV_8U);
Mat laplacianImage8bit = new Mat();
laplacianImage.convertTo(laplacianImage8bit, l);
Bitmap bmp = Bitmap.createBitmap(laplacianImage8bit.cols(), laplacianImage8bit.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(laplacianImage8bit, bmp);
int[] pixels = new int[bmp.getHeight() * bmp.getWidth()];
bmp.getPixels(pixels, 0, bmp.getWidth(), 0, 0, bmp.getWidth(), bmp.getHeight()); // bmp为轮廓图
int maxLap = -16777216; // 16m
for (int pixel : pixels) {
if (pixel > maxLap)
maxLap = pixel;
}
int soglia = -6118750;
if (maxLap <= soglia) {
System.out.println("is blur image");
}
soglia += 6118750;
maxLap += 6118750;
LogUtil.log("图片位置=" + picFilePath
+ "\nimage.w=" + image.getWidth() + ", image.h=" + image.getHeight()
+ "\nmaxLap= " + maxLap + "(清晰范围:0~6118750)"
+ "\n" + Html.fromHtml("<font color='#eb5151'><b>" + (maxLap <= soglia ? "模糊" : "清晰") + "</b></font>"));
opencvEnd = true;
isBlur = maxLap <= soglia;
}