Image Detection Open CV - java

So I'm trying to draw a rect around an image. I'm finding a sub image from a larger image using Open CV. How I calculated it was to convert both the template image (target) and the target image (scene) to HSV and get the back projection of the object and compare it with the scene image which is saturated. Works a bit. (Would be glad for any improvements). Basically i want to draw a rect around the image and extract the found rect from the scene unto a Mat. I've tried a doing it a couple of ways but doesn't seem to be working. Here's my code. My question is how do I get the sub image from the target image?
public List<DMatch> subListGoodMatches(List<DMatch> good_matches) {
Collections.sort(good_matches, (DMatch o1, DMatch o2) -> {
if (o1.distance < o2.distance) {
return -1;
}
if (o1.distance > o2.distance) {
return 1;
}
return 0;
});
if (good_matches.size() > 10) {
good_matches = good_matches.subList(0, 10);
}
return good_matches;
}
public List<Mat> calculateHistograms(Mat image) {
Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2HSV);
List<Mat> hsv_planes = new ArrayList<Mat>();
Core.split(image, hsv_planes);
MatOfInt histSize = new MatOfInt(256);
final MatOfFloat histRange = new MatOfFloat(0f, 256f);
boolean accumulate = true;
Mat h_hist = new Mat();
Mat s_hist = new Mat();
Mat v_hist = new Mat();
//Break channels
List<Mat> h_plane = new ArrayList<Mat>();
List<Mat> s_plane = new ArrayList<Mat>();
List<Mat> v_plane = new ArrayList<Mat>();
h_plane.add(hsv_planes.get(0));
s_plane.add(hsv_planes.get(1));
v_plane.add(hsv_planes.get(2));
Imgproc.calcHist(h_plane, new MatOfInt(0), new Mat(), h_hist, histSize, histRange, accumulate);
Imgproc.calcHist(s_plane, new MatOfInt(0), new Mat(), s_hist, histSize, histRange, accumulate);
Imgproc.calcHist(v_plane, new MatOfInt(0), new Mat(), v_hist, histSize, histRange, accumulate);
//Draw combined histograms
int hist_w = 512;
int hist_h = 600;
long bin_w = Math.round((double) hist_w / 256);
Mat histImage = new Mat(hist_h, hist_w, CvType.CV_8UC3, new Scalar(0, 0, 0));
Core.normalize(h_hist, h_hist, 3, histImage.rows(), Core.NORM_MINMAX, -1, new Mat());
Core.normalize(s_hist, s_hist, 3, histImage.rows(), Core.NORM_MINMAX, -1, new Mat());
Core.normalize(v_hist, v_hist, 3, histImage.rows(), Core.NORM_MINMAX, -1, new Mat());
for (int i = 1; i < 256; i++) {
Point p1 = new Point(bin_w * (i - 1), hist_h - Math.round(h_hist.get(i - 1, 0)[0]));
Point p2 = new Point(bin_w * (i), hist_h - Math.round(h_hist.get(i, 0)[0]));
Core.line(histImage, p1, p2, RED, 2, 8, 0);
Point p3 = new Point(bin_w * (i - 1), hist_h - Math.round(s_hist.get(i - 1, 0)[0]));
Point p4 = new Point(bin_w * (i), hist_h - Math.round(s_hist.get(i, 0)[0]));
Core.line(histImage, p3, p4, GREEN, 2, 8, 0);
Point p5 = new Point(bin_w * (i - 1), hist_h - Math.round(v_hist.get(i - 1, 0)[0]));
Point p6 = new Point(bin_w * (i), hist_h - Math.round(v_hist.get(i, 0)[0]));
Core.line(histImage, p5, p6, BLUE, 2, 8, 0);
}
Highgui.imwrite("img-histogram.jpg", histImage);
System.out.println("Hist size is: " + hsv_planes.size());
List<Mat> histograms = new ArrayList<Mat>();
histograms.add(h_hist);
histograms.add(s_hist);
histograms.add(v_hist);
return histograms;
}
public Mat identifyLowSat(Mat image) {
Mat hsvTargetImage = new Mat();
Imgproc.cvtColor(image, hsvTargetImage, Imgproc.COLOR_BGR2HSV);
List<Mat> hsv_planes = new ArrayList<Mat>();
Core.split(hsvTargetImage, hsv_planes);
//Get saturation channel
Mat s_hist = hsv_planes.get(1);
Imgproc.threshold(s_hist, s_hist, 65, 255, Imgproc.THRESH_BINARY);
Highgui.imwrite("img-saturation.png", s_hist);
return s_hist;
}
public Mat getBackProjOfHueTemplate(Mat image, Mat hue_histogram) {
Mat hsvTargetImage = new Mat();
Imgproc.cvtColor(image, hsvTargetImage, Imgproc.COLOR_BGR2HSV);
List<Mat> hsv_planes = new ArrayList<Mat>();
Core.split(hsvTargetImage, hsv_planes);
Mat backProj = new Mat();
final MatOfFloat range = new MatOfFloat(0f, 256f);
Imgproc.calcBackProject(hsv_planes, new MatOfInt(0), hue_histogram, backProj, range, 4);
Highgui.imwrite("img-backProj.png", backProj);
return backProj;
}
public Mat meanShift(Mat image) {
Mat map = new Mat();
Rect rect = new Rect();
TermCriteria term = new TermCriteria();
term.maxCount = 100;
term.type = TermCriteria.EPS;
term.epsilon = 0.1;
Imgproc.pyrMeanShiftFiltering(image, map, 0.5, 0.5, 5, term);
Highgui.imwrite("img-meanshift.png", map);
return map;
}
public MatOfDMatch filterMatches(Mat img1, Mat img2) {
FeatureDetector detector = FeatureDetector.create(FeatureDetector.SIFT);
DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.BRISK);
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
// First photo
//Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGB2GRAY);
Mat descriptors1 = new Mat();
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
detector.detect(img1, keypoints1);
descriptor.compute(img1, keypoints1, descriptors1);
// Second photo
//Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGB2GRAY);
Mat descriptors2 = new Mat();
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
detector.detect(img2, keypoints2);
descriptor.compute(img2, keypoints2, descriptors2);
// Matching
MatOfDMatch matches = new MatOfDMatch();
MatOfDMatch filteredMatches = new MatOfDMatch();
matcher.match(descriptors1, descriptors2, matches);
List<DMatch> matchesList = matches.toList();
Double max_dist = Double.MIN_VALUE;
Double min_dist = Double.POSITIVE_INFINITY;
for (DMatch matchesList1 : matchesList) {
Double dist = (double) matchesList1.distance;
if (dist < min_dist) {
min_dist = dist;
}
if (dist > max_dist) {
max_dist = dist;
}
}
LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
for (DMatch matchesList1 : matchesList) {
if (matchesList1.distance <= (1.5 * min_dist)) {
good_matches.addLast(matchesList1);
}
}
MatOfDMatch goodMatches = new MatOfDMatch();
//goodMatches.fromList(good_matches);
List<DMatch> newGood_Matches = subListGoodMatches(good_matches);
goodMatches.fromList(newGood_Matches);
//put keypoints mats into lists
List<KeyPoint> keypoints1_List = keypoints1.toList();
List<KeyPoint> keypoints2_List = keypoints2.toList();
//put keypoints into point2f mats so calib3d can use them to find homography
LinkedList<Point> objList = new LinkedList<Point>();
LinkedList<Point> sceneList = new LinkedList<Point>();
for (int i = 0; i < newGood_Matches.size(); i++) {
objList.addLast(keypoints2_List.get(newGood_Matches.get(i).trainIdx).pt);
sceneList.addLast(keypoints1_List.get(newGood_Matches.get(i).queryIdx).pt);
}
MatOfPoint2f obj = new MatOfPoint2f();
MatOfPoint2f scene = new MatOfPoint2f();
obj.fromList(objList);
scene.fromList(sceneList);
System.out.println(matches.size() + " " + goodMatches.size());
//output image
Mat outputImg = new Mat();
MatOfByte drawnMatches = new MatOfByte();
Features2d.drawMatches(img1, keypoints1, img2, keypoints2, goodMatches, outputImg, Scalar.all(-1), Scalar.all(-1), drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);
Highgui.imwrite("img-matches.png", outputImg);
drawWithRect(img1, img2, obj, scene, outputImg);
keypointers1 = keypoints1;
keypointers2 = keypoints2;
return goodMatches;
}
public MatOfDMatch filterMatchesByHomography(MatOfDMatch matches) {
MatOfKeyPoint keypoints1 = keypointers1;
MatOfKeyPoint keypoints2 = keypointers2;
List<Point> lp1 = new ArrayList<Point>();
List<Point> lp2 = new ArrayList<Point>();
KeyPoint[] k1 = keypoints1.toArray();
KeyPoint[] k2 = keypoints2.toArray();
List<DMatch> matches_original = matches.toList();
if (matches_original.size() < 4) {
MatOfDMatch mat = new MatOfDMatch();
return mat;
}
// Add matches keypoints to new list to apply homography
for (DMatch match : matches_original) {
Point kk1 = k1[match.queryIdx].pt;
Point kk2 = k2[match.trainIdx].pt;
lp1.add(kk1);
lp2.add(kk2);
}
//srcPoints = new MatOfPoint2f(lp1.toArray(new Point[0]));
//dstPoints = new MatOfPoint2f(lp2.toArray(new Point[0]));
Mat mask = new Mat();
//Mat homography = Calib3d.findHomography(srcPoints, dstPoints, Calib3d.LMEDS, 0.2, mask);
List<DMatch> matches_homo = new ArrayList<DMatch>();
int size = (int) mask.size().height;
for (int i = 0; i < size; i++) {
if (mask.get(i, 0)[0] == 1) {
DMatch d = matches_original.get(i);
matches_homo.add(d);
}
}
MatOfDMatch mat = new MatOfDMatch();
mat.fromList(matches_homo);
//Highgui.imwrite("img-matchesWithRect.png", mat);
return mat;
}
public void drawMatches(Mat img1, Mat img2, MatOfDMatch matches, boolean imageOnly) {
Mat out = new Mat();
MatOfKeyPoint key2 = keypointers2;
MatOfKeyPoint key1 = keypointers1;
//Imgproc.cvtColor(img1, im1, Imgproc.COLOR_BGR2RGB);
//Imgproc.cvtColor(img2, im2, Imgproc.COLOR_BGR2RGB);
if (imageOnly) {
MatOfDMatch emptyMatch = new MatOfDMatch();
MatOfKeyPoint emptyKey1 = new MatOfKeyPoint();
MatOfKeyPoint emptyKey2 = new MatOfKeyPoint();
Features2d.drawMatches(img1, emptyKey1, img2, emptyKey2, emptyMatch, out);
} else {
Features2d.drawMatches(img1, key1, img2, key2, matches, out);
}
//Imgproc.cvtColor(out, out, Imgproc.COLOR_BGR2RGB);
Core.putText(out, "FRAME", new Point(img1.width() / 2, 30), Core.FONT_HERSHEY_PLAIN, 2, new Scalar(0, 255, 255), 3);
Core.putText(out, "MATCHED", new Point(img1.width() + img2.width() / 2, 30), Core.FONT_HERSHEY_PLAIN, 2, new Scalar(255, 0, 0), 3);
Highgui.imwrite("img-drawnMatches.png", out);
}
public void drawWithRect(Mat img1, Mat img2, MatOfPoint2f obj, MatOfPoint2f scene, Mat outputImg){
//run homography on object and scene points
Mat H = Calib3d.findHomography(obj, scene, Calib3d.RANSAC, 5);
Mat tmp_corners = new Mat(4, 1, CvType.CV_32FC2);
Mat scene_corners = new Mat(4, 1, CvType.CV_32FC2);
//get corners from object
tmp_corners.put(0, 0, new double[]{0, 0});
tmp_corners.put(1, 0, new double[]{img2.cols(), 0});
tmp_corners.put(2, 0, new double[]{img2.cols(), img2.rows()});
tmp_corners.put(3, 0, new double[]{0, img2.rows()});
Core.perspectiveTransform(tmp_corners, scene_corners, H);
Core.line(outputImg, new Point(scene_corners.get(0, 0)), new Point(scene_corners.get(1, 0)), new Scalar(0, 255, 0), 4);
Core.line(outputImg, new Point(scene_corners.get(1, 0)), new Point(scene_corners.get(2, 0)), new Scalar(0, 255, 0), 4);
Core.line(outputImg, new Point(scene_corners.get(2, 0)), new Point(scene_corners.get(3, 0)), new Scalar(0, 255, 0), 4);
Core.line(outputImg, new Point(scene_corners.get(3, 0)), new Point(scene_corners.get(0, 0)), new Scalar(0, 255, 0), 4);
Highgui.imwrite("img-matchesWithRect.png", outputImg);
}
Main method:
public static void main(String args[]) {
System.load(new File("/usr/local/Cellar/opencv/2.4.9/share/OpenCV/java/libopencv_java249.dylib").getAbsolutePath());
Mat img1 = Highgui.imread(scenesD);
Mat img2 = Highgui.imread(objectD);
MeanShift Tester = new MeanShift();
List<Mat> histogramsList;
Mat hue_histogram;
Mat saturationChannel;
Mat getBackProjOfHueTemp;
//Calulate Histogram of Object
histogramsList = Tester.calculateHistograms(img2);
//Get saturation channel of scene
saturationChannel = Tester.identifyLowSat(img1);
//Get hue of calculated object histogram
hue_histogram = histogramsList.get(0);
//Get back projection of object from calculated hue histogram template
getBackProjOfHueTemp = Tester.getBackProjOfHueTemplate(img2, hue_histogram);
//Filtering matches
MatOfDMatch matches = Tester.filterMatches(saturationChannel, getBackProjOfHueTemp);
MatOfDMatch homo_matches = Tester.filterMatchesByHomography(matches);
//Draw img unto screen;
Tester.drawMatches(saturationChannel, getBackProjOfHueTemp, homo_matches, false);
}
And so far here's the final image i get (img-matches.png)
And trying to get the rect from the image gives me this (img-matchesWithRect.png)

Ok, so you have the Points in your original image that you found have matches in your target image. These points all have x and y coordinates - to find the "subimage" (or a rectangle in the image), all you need to do is take the minimum of all the x's to get your top left x coordinate, the minimum of the ys to get your top left y coordinate, the max of the xs to get your bottom right x coordinate, and the max of the ys to get your bottom right y coordinate.
Then with these you can create a Rect (http://docs.opencv.org/java/org/opencv/core/Rect.html) and use it to access the subimage: image(Rect) (assuming you have a previous variable image that is a Mat):
Rect sub_rect = new Rect(min_x, min_y, max_x - min_x, max_y - min_y);
Mat sub_region = image(sub_rect);
Now sub_region will have your subregion in it.

Related

Android canny, hough transform. I want to go back to original image

Android, I used canny and hough transform to make line detection on phone screen. However, I can't find a way to get back to original image(I mean HSV to BGR). I want to see keep lines well with BGR image. Thank you!
My code, please let me know which code I have to put in.
public class CameraActivity extends Activity implements CameraBridgeViewBase.CvCameraViewListener2{
private static final String TAG="MainActivity";
private Mat mRgba;
private Mat mGray;
Scalar scalarLow,scalarHigh;///
Mat mat1,mat2;////
Rect rect;////
Rect roi_rect;///
private Mat m_matRoi;////
Point rect1, rect2;///////
public void onCameraViewStarted(int width ,int height){
mRgba=new Mat(height,width, CvType.CV_8UC4);
mGray =new Mat(height,width,CvType.CV_8UC1);
mat1 = new Mat(height,width,CvType.CV_8UC4);
mat2 = new Mat(height,width,CvType.CV_8UC4);
}
public void onCameraViewStopped(){
mRgba.release();
}
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){
mRgba=inputFrame.rgba();/////mRgba = image, matInput 과 같은 역할
mGray=inputFrame.gray();
double m_dWscale = (double) 1/3;
double m_dHscale = (double) 1/4;
int mRoiWidth = (int)(mRgba.size().width * m_dWscale);
int mRoiHeight = (int)(mRgba.size().height * m_dHscale);
int mRoiX = (int) (mRgba.size().width - mRoiWidth) ;
int mRoiY = (int) (mRgba.size().height - mRoiHeight) ;
//rect = new Rect(mRoiX,mRoiY,mRoiWidth,mRoiHeight);
rect1 =new Point(mRoiX, mRoiY);
rect2 = new Point(mRoiWidth,mRoiHeight);
Imgproc.rectangle(mRgba,rect1,rect2,new Scalar(0, 255, 0, 255),5);
roi_rect = new Rect(mRoiX+4,mRoiY+4,mRoiWidth-8,mRoiHeight-8);
m_matRoi = mRgba.submat(roi_rect);
Mat temp = new Mat();
Imgproc.cvtColor(m_matRoi, temp, Imgproc.COLOR_BGRA2GRAY,0);
Mat temp_rgba = new Mat();
Imgproc.cvtColor(temp, temp_rgba, Imgproc.COLOR_GRAY2BGRA,0);
temp_rgba.copyTo(m_matRoi);
scalarLow=new Scalar(0,0,200);
scalarHigh=new Scalar(180,255,255);
Imgproc.cvtColor(mRgba,mat1,Imgproc.COLOR_BGR2HSV);
Core.inRange(mat1,scalarLow,scalarHigh,mat2);
Core.bitwise_and(mRgba,mRgba,mat1,mat2);
mRgba=mat1;
Imgproc.dilate(mRgba,mRgba,new Mat(),new Point(1,2),2);//
Mat edges=new Mat();
Imgproc.Canny(mRgba,edges,90,150);
Mat lines=new Mat();
Point p1=new Point();
Point p2=new Point();
double a,b;
double x0,y0;
Imgproc.HoughLinesP(edges,lines,1.0,Math.PI/180.0,50,100.0,10.0);//
for(int i=0;i<lines.rows();i++) {
double[] l = lines.get(i, 0);
Imgproc.line(mRgba, new Point(l[0], l[1]), new Point(l[2], l[3]), new Scalar(0, 0, 255.0), 3);
}
return mRgba;
}
}
I divided it to two parts b/c there were not necessary codes between them.
Thank you.
Edit1)
To #Jeru Luke, I changed the code you said. I put many slashes where I changed the code.
public void onCameraViewStarted(int width ,int height){
mRgba=new Mat(height,width, CvType.CV_8UC4);
mGray =new Mat(height,width,CvType.CV_8UC1);
mat1 = new Mat(height,width,CvType.CV_8UC4);
mat2 = new Mat(height,width,CvType.CV_8UC4);//////////
}
public void onCameraViewStopped(){
mRgba.release();
}
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){
mRgba=inputFrame.rgba();/////mRgba = image, matInput 과 같은 역할
mGray=inputFrame.gray();
double m_dWscale = (double) 1/3;
double m_dHscale = (double) 1/4;
int mRoiWidth = (int)(mRgba.size().width * m_dWscale);
int mRoiHeight = (int)(mRgba.size().height * m_dHscale);
int mRoiX = (int) (mRgba.size().width - mRoiWidth) ;
int mRoiY = (int) (mRgba.size().height - mRoiHeight) ;
//rect = new Rect(mRoiX,mRoiY,mRoiWidth,mRoiHeight);
rect1 =new Point(mRoiX, mRoiY);
rect2 = new Point(mRoiWidth,mRoiHeight);
Imgproc.rectangle(mRgba,rect1,rect2,new Scalar(0, 255, 0, 255),5);
roi_rect = new Rect(mRoiX+4,mRoiY+4,mRoiWidth-8,mRoiHeight-8);
m_matRoi = mRgba.submat(roi_rect);
Mat temp = new Mat();
Imgproc.cvtColor(m_matRoi, temp, Imgproc.COLOR_BGRA2GRAY,0);
Mat temp_rgba = new Mat();
Imgproc.cvtColor(temp, temp_rgba, Imgproc.COLOR_GRAY2BGRA,0);
temp_rgba.copyTo(m_matRoi);
scalarLow=new Scalar(0,0,200);
scalarHigh=new Scalar(180,255,255);
Imgproc.cvtColor(mRgba,mat1,Imgproc.COLOR_BGR2HSV);
Core.inRange(mat1,scalarLow,scalarHigh,mat2);
Core.bitwise_and(mRgba,mRgba,mat1,mat2);
mRgba=mat2;////////////////////////////////////
Imgproc.dilate(mat1,mRgba,new Mat(),new Point(1,2),2);/////////////
Mat edges=new Mat();
Imgproc.Canny(mat1,edges,90,150);//////////////////////////
Mat lines=new Mat();
Point p1=new Point();
Point p2=new Point();
double a,b;
double x0,y0;
Imgproc.HoughLinesP(edges,lines,1.0,Math.PI/180.0,50,100.0,10.0);
for(int i=0;i<lines.rows();i++) {
double[] l = lines.get(i, 0);
Imgproc.line(mRgba, new Point(l[0], l[1]), new Point(l[2], l[3]), new Scalar(0, 0, 255.0), 3);
Scalar(255.0,255.0,255.0),1,Imgproc.LINE_AA,0);
}
return mRgba;
}
}
Edit2) My final objective of this project is draw lines only in ROI(Region of Interest) area. Below code is about ROI. But the problem is it only shows rectangular box and lines are everywhere in my phone screen.
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){
mRgba=inputFrame.rgba();
mGray=inputFrame.gray();
mat3=inputFrame.rgba();
double m_dWscale = (double) 1/3;
double m_dHscale = (double) 1/4;
int mRoiWidth = (int)(mRgba.size().width * m_dWscale);
int mRoiHeight = (int)(mRgba.size().height * m_dHscale);
int mRoiX = (int) (mRgba.size().width - mRoiWidth) ;
int mRoiY = (int) (mRgba.size().height - mRoiHeight) ;
//rect = new Rect(mRoiX,mRoiY,mRoiWidth,mRoiHeight);
rect1 =new Point(mRoiX, mRoiY);
rect2 = new Point(mRoiWidth,mRoiHeight);
Imgproc.rectangle(mRgba,rect1,rect2,new Scalar(0, 255, 0, 255),5);
roi_rect = new Rect(mRoiX+4,mRoiY+4,mRoiWidth-8,mRoiHeight-8);
m_matRoi = mRgba.submat(roi_rect);
//Mat temp = new Mat();
//Imgproc.cvtColor(m_matRoi, temp, Imgproc.COLOR_BGRA2GRAY,0);
//Mat temp_rgba = new Mat();
//Imgproc.cvtColor(temp, temp_rgba, Imgproc.COLOR_GRAY2BGRA,0);
//temp_rgba.copyTo(m_matRoi);
this part is about ROI.
Edit3) below code is about making mask I guess..
roi_rect = new Rect(mRoiX,mRoiY,mRoiWidth,mRoiHeight);
mat5 = mRgba.submat(roi_rect);
//Mat temp = new Mat();
//Mat temp_rgba = new Mat();
Imgproc.cvtColor(mRgba,mRgba,Imgproc.COLOR_BGR2GRAY);
Imgproc.cvtColor(mat5, mat5, Imgproc.COLOR_GRAY2BGR,0); //
//Imgproc.cvtColor(temp, temp_rgba, Imgproc.COLOR_GRAY2BGRA,0);
mat5.copyTo(mRgba);
roi_rect 's parameters are all (int) and mat5 is
mat5 = new Mat(height,width,CvType.CV_8UC4);
I made this code firstly to make all region dark. And using roi_rect only that part, which means mat5 is converted GRAY2BGR and then use mat5.copyTo(mRgba) to paste mat5 on mRgba. But it shuts down when I turn on the app.

Detect Biggest Rectangle in the Image using Java Opencv [SOLVED]

How can I detect the four corner points of the biggest square (at center of the image) using opencv in java
I have solved this using findContours.
Original Image
Output Image
Please find the code below. I don't now how to detect the end points of center square. I tried to detect lines using HoughLinesP but it is returning only 1 verticle line instead of giving all the 4 lines.
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
String path = "/Users/saurabhsaluja/Desktop/cimg.jpg";
Mat img = Imgcodecs.imread(path);
Mat destination = new Mat(img.rows(),img.cols(),img.type());
Core.addWeighted(img, 1.3, destination, -0.7, 0, destination);
Mat cannyOutput = new Mat();
int threshold = 15;
Mat srcGray = new Mat();
Imgproc.cvtColor(destination, srcGray, Imgproc.COLOR_BGR2GRAY);
Imgproc.Canny(srcGray, cannyOutput, threshold, threshold* 4);
Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,10));
Mat element2 = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,10));
Imgproc.dilate(cannyOutput, cannyOutput, element);
Imgproc.dilate(cannyOutput, cannyOutput, element2);
element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(9,9));
element2 = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(9,9));
Imgproc.erode(cannyOutput, cannyOutput, element);
Imgproc.erode(cannyOutput, cannyOutput, element2);
Imgcodecs.imwrite("/Users/saurabhsaluja/Desktop/cannyOutput.jpg", cannyOutput); //THE IMAGE YOU ARE LOOKING AT
Mat lines = new Mat();
Imgproc.HoughLinesP(cannyOutput, lines, 1, Math.PI / 180, 50, 20, 20);
for(int i = 0; i < lines.cols(); i++) {
double[] val = lines.get(0, i);
Imgproc.line(img, new Point(val[0], val[1]), new Point(val[2], val[3]), new Scalar(0, 0, 255), 2);
}
Imgcodecs.imwrite("/Users/saurabhsaluja/Desktop/finalimg.jpg", img);
Solution:
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(cannyOutput, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double inf = 0;
Rect max_rect = null;
for(int i=0; i< contours.size();i++){
Rect rect = Imgproc.boundingRect(contours.get(i));
double area = rect.area();
if(inf < area) {
max_rect = rect;
inf = area;
//Imgcodecs.imwrite("/Users/saurabhsaluja/Desktop/input"+i+".jpg", img);
}
if(area > 50000) {
System.out.println(area);
Imgproc.rectangle(img, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height),new Scalar(0,0,0),5);
}
}
Now just get the biggest by looking area of each counter.
Thanks.
Solution Image:
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(cannyOutput, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double inf = 0;
Rect max_rect = null;
for(int i=0; i< contours.size();i++){
Rect rect = Imgproc.boundingRect(contours.get(i));
double area = rect.area();
if(inf < area) {
max_rect = rect;
inf = area;
//Imgcodecs.imwrite("/Users/saurabhsaluja/Desktop/input"+i+".jpg", img);
}
if(area > 50000) {
System.out.println(area);
Imgproc.rectangle(img, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height),new Scalar(0,0,0),5);
}
}
Output:

Java OCR Not reading clearly obvious numbers

picture of processed image + original
I'm working on a project where I'm taking Smash Bros. game output, taking a screenshot, processing it in order to detect the percents which the characters are sitting at.
The program I wrote is detecting the 57 as a 55 and the 11 (which I let settle to it's normal position) as a 51. And while the gameplay is running, the numbers will jump around.
The program I wrote uses Tess4J, and I've configured everything right. I have trained Tesseract with my own custom font that I made using the games percentage numbers. I've tried multiple different fonts as well. What will make it more accurate!?
I've thought about instead of calculating percents, instead just detecting when they're damaged, but I'm also figuring that out.
This is the code I use to process images:
public static Mat blur(Mat input, int numberOfTimes){
Mat sourceImage = new Mat();
Mat destImage = input.clone();
for(int i=0;i<numberOfTimes;i++){
sourceImage = destImage.clone();
Imgproc.blur(sourceImage, destImage, new Size(3.0, 3.0));
}
return destImage;
}
public static BufferedImage purify(BufferedImage image) {
BufferedImage image2 = ImageHelper.convertImageToGrayscale(image);
Mat mat = BufferedImage2Mat(image2, -1);
Mat resizedMat = new Mat();
double width = mat.cols();
double height = mat.rows();
double aspect = width / height;
Size sz = new Size(width * aspect * 1.4, height * aspect * 1.4);
Imgproc.resize(mat, resizedMat, sz);
double thresh = Imgproc.threshold(resizedMat, resizedMat, 23, 255, Imgproc.THRESH_BINARY_INV);
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
Imgproc.dilate(resizedMat, resizedMat, kernel, new Point(0, 0), 9);
return toBufferedImage(HighGui.toBufferedImage(blur(resizedMat, 0)));
}
public static BufferedImage toBufferedImage(Image img)
{
if (img instanceof BufferedImage)
{
return (BufferedImage) img;
}
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
return bimage;
}
public static Image denoise(BufferedImage img) {
Mat image = BufferedImage2Mat(img, 0);
Mat out = new Mat();
Mat tmp = new Mat();
Mat kernel = new Mat(new Size(3, 3), CvType.CV_8UC1, new Scalar(255));
Imgproc.morphologyEx(image, tmp, Imgproc.MORPH_OPEN, kernel);
Imgproc.morphologyEx(tmp, out, Imgproc.MORPH_CLOSE, kernel);
return HighGui.toBufferedImage(out);
}
public static Mat BufferedImage2Mat(BufferedImage image, int filter) {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", byteArrayOutputStream);
byteArrayOutputStream.flush();
return Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), filter);
} catch (IOException e) {
return null;
}
}
public static Image clean(BufferedImage image) {
Mat og = BufferedImage2Mat(image, Imgcodecs.IMREAD_UNCHANGED);
Mat im = BufferedImage2Mat(image, 0);
Mat bw = new Mat(im.size(), CvType.CV_8U);
Imgproc.threshold(im, bw, 0, 255, Imgproc.THRESH_BINARY_INV | Imgproc.THRESH_OTSU);
Mat dist = new Mat(im.size(), CvType.CV_32F);
Imgproc.distanceTransform(bw, dist, Imgproc.CV_DIST_L2, Imgproc.CV_DIST_MASK_PRECISE);
Mat dibw32f = new Mat(im.size(), CvType.CV_32F);
final double SWTHRESH = 8.0; // stroke width threshold
Imgproc.threshold(dist, dibw32f, SWTHRESH/2.0, 255, Imgproc.THRESH_BINARY);
Mat dibw8u = new Mat(im.size(), CvType.CV_8U);
dibw32f.convertTo(dibw8u, CvType.CV_8U);
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
Mat cont = new Mat(im.size(), CvType.CV_8U);
Imgproc.morphologyEx(dibw8u, cont, Imgproc.MORPH_OPEN, kernel);
final double HTHRESH = im.rows() * 0.5;
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<Point> digits = new ArrayList<Point>();
Mat hierchy = new Mat();
Imgproc.findContours(cont, contours, hierchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
List<Mat>cleanedMatList = new ArrayList<Mat>();
int c = 0;
for (int i = 0; i >= hierchy.cols(); i++) {
Rect rect = Imgproc.boundingRect(contours.get(i));
if (rect.height > HTHRESH) {
Mat binary = new Mat();
Imgproc.rectangle(binary, new Point(rect.x, rect.y), new Point(rect.x + rect.width - 1, rect.y + rect.height - 1), new Scalar(0, 0, 255), 3);
cleanedMatList.add(c, binary);
c++;
}
}
List<MatOfInt> digitsHull = new ArrayList<MatOfInt>();
for(int i=0; i < contours.size(); i++){
digitsHull.add(new MatOfInt());
}
for(int i=0; i < contours.size(); i++){
Imgproc.convexHull(contours.get(i), digitsHull.get(i));
}
List<MatOfPoint> digitRegions = new ArrayList<MatOfPoint>();
for (int i = 0; i< digitRegions.size(); i++) {
MatOfPoint dr = digitRegions.get(i);
dr.push_back(digitsHull.get(i));
}
Mat digitsMask = new Mat(og.rows(),og.cols(), CvType.CV_8U);
Imgproc.drawContours(digitsMask, digitRegions, 0, new Scalar(255, 255, 255), -1);
Imgproc.morphologyEx(digitsMask, digitsMask, Imgproc.MORPH_DILATE, kernel);
Mat cleaned = new Mat(og.rows(), og.cols(), CvType.CV_8U);
dibw8u.copyTo(cleaned, digitsMask);
return HighGui.toBufferedImage(dibw8u);
}

How can I order the contours in an orderly manner from top to bottom from left to right?

I have to take shelf plans. I would like to order them as if it were a matrix where [0,0] was at the bottom left or top left.
I need this because there will be a database with coordinates to take something on the shelf.
But findContours takes the contours randomly and I don't know how to sort them.
How can I do?
I hope I was clear.
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
Mat img = inputFrame.rgba();
Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY, 0);
Imgproc.Canny(gray, gray, 100, 255, 3, true);
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, kernelSize);
Imgproc.dilate(gray, gray, kernel);
Imgproc.GaussianBlur(gray, gray, new Size(3, 3), 0);
List < MatOfPoint > contours = new ArrayList < MatOfPoint > ();
Imgproc.findContours(gray, contours, hierarchy, Imgproc.RETR_TREE,
Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint2f approxCurve = new MatOfPoint2f();
//For each contour found
for (int i = 0; i < contours.size(); i++) {
//convert contours(i) from MatOfPoint to MatOfPoint2f
MatOfPoint2f contour2f = new
MatOfPoint2f(contours.get(i).toArray());
double approxDistance = Imgproc.arcLength(contour2f, true) * 0.05;
Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);
//convert back to MatOfPoint
MatOfPoint points = new MatOfPoint(approxCurve.toArray());
//SORT POINTs
//Get bounding rect of contour
Rect rect = Imgproc.boundingRect(points);
//draw enclosing rectangle
if (rect.height > 200 && rect.width > 200)
// Imgproc.rectangle(img,new Point(rect.x,rect.y),new
Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 0, 255), 4);
Imgproc.rectangle(img, rect.tl(), rect.br(), new Scalar(0, 0, 255), 4);
}
return img;
}

org.Opencv.core.Mat cannot be Cast to java.util.list in android studio

I am trying to calculate a histogram using opencv 2_4_9 to show in one of my activities but this error is keep popping up i have searched it everywhere i couldn't find any solution specifically to my problem if anyone could help me how to solve it..!!
private void GetResult()
{
try
{
// System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
img = BitmapFactory.decodeFile(outPutFile.toString());
image = new Mat(img.getHeight(), img.getWidth(), CvType.CV_8UC1);
Utils.bitmapToMat(img, image);
Imgproc.cvtColor(image, image, Imgproc.COLOR_RGB2HSV);
List<Mat> hsv_planes = new ArrayList<Mat>();
//splitting into 3 planes r,g,b
Core.split(image, hsv_planes);
//the number of bins
MatOfInt HistSize = new MatOfInt(256);
//set the ranges for r,g,b
final MatOfFloat HistRange = new MatOfFloat(0f, 256f);
boolean accumulate = false;
Mat h_hist = new Mat();
Mat s_hist = new Mat();
Mat v_hist = new Mat();
//Compute the histograms using calcHist function
Imgproc.calcHist((List<Mat>) hsv_planes.get(0), new MatOfInt(3), new Mat(), h_hist, HistSize, HistRange, accumulate);
Imgproc.calcHist((List<Mat>) hsv_planes.get(1), new MatOfInt(3), new Mat(), s_hist, HistSize, HistRange, accumulate);
Imgproc.calcHist((List<Mat>) hsv_planes.get(2), new MatOfInt(3), new Mat(), v_hist, HistSize, HistRange, accumulate);
int hist_w = 512;
int hist_h = 600;
long bin_w = Math.round((double) hist_w / 256);
Mat HistImage = new Mat(hist_h, hist_w, CvType.CV_8UC1);
//Normalization
Core.normalize(h_hist, h_hist, 3, HistImage.rows(), Core.NORM_MINMAX);
Core.normalize(s_hist, s_hist, 3, HistImage.rows(), Core.NORM_MINMAX);
Core.normalize(v_hist, v_hist, 3, HistImage.rows(), Core.NORM_MINMAX);
for (int i = 1; i < 256; i++) {
Point p1 = new Point(bin_w * (i - 1), hist_h - Math.round(h_hist.get(i - 1, 0)[0]));
Point p2 = new Point(bin_w * (i), hist_h - Math.round(h_hist.get(i, 0)[0]));
Core.line(HistImage, p1, p2, new Scalar(255, 0, 0), 2, 8, 0);
Point p3 = new Point(bin_w * (i - 1), hist_h - Math.round(s_hist.get(i - 1, 0)[0]));
Point p4 = new Point(bin_w * (i), hist_h - Math.round(s_hist.get(i, 0)[0]));
Core.line(HistImage, p3, p4, new Scalar(255, 0, 0), 2, 8, 0);
Point p5 = new Point(bin_w * (i - 1), hist_h - Math.round(v_hist.get(i - 1, 0)[0]));
Point p6 = new Point(bin_w * (i), hist_h - Math.round(v_hist.get(i, 0)[0]));
Core.line(HistImage, p1, p2, new Scalar(255, 0, 0), 2, 8, 0);
}
Utils.matToBitmap(HistImage, photoo);
img_histogram.setImageBitmap(photoo);
}
catch (Exception e)
{
Toast.makeText(MainActivity.this, e.toString(),Toast.LENGTH_LONG).show();
}
}
}
You try to cast a Mat to a List of Mat objects which isn't possible.
Initialize arrays for the different planes. For example:
List<Mat> hList = new ArrayList<>();
hList.add(hsv_planes.get(0));
List<Mat> sList = new ArrayList<>();
sList.add(hsv_planes.get(1));
List<Mat> vList = new ArrayList<>();
vList.add(hsv_planes.get(2));
//Compute the histograms using calcHist function
Imgproc.calcHist(hList, new MatOfInt(3), new Mat(), h_hist, HistSize, HistRange, accumulate);
Imgproc.calcHist(sList, new MatOfInt(3), new Mat(), s_hist, HistSize, HistRange, accumulate);
Imgproc.calcHist(vList, new MatOfInt(3), new Mat(), v_hist, HistSize, HistRange, accumulate);

Categories

Resources