I'm trying to develop an application with android studio to capture the color of flashing LEDs.
Im now at this Point, that i got the positions of the LEDs and now i want to determine the bounding box center with the class moments of openCV.
Mat src = new.Mat(Bitmap.getHeight(), Bitmap.getWidth(), CvType.CV_8UC1);
Mat hsv = new Mat();
Utils.bitmapToMat(Bitmap, src);
Imgproc.cvtColor(src,hsv, Imgproc.COLOR_BGR2HSV);
Core.inRange(hsv,LOWER_RED,HIGHER_RED,hsv);
Imgproc.dilate(hsv,hsv,Imgproc.getStructuringElement(Imgproc.MORPH_VECT,new Size(50,50)));
List<MatOfPoint> contours = new ArrayList <>();
Mat hierarchy = new Mat();
Imgproc.findContours(hsv, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
hierarchy.release();
//finding Bounding Box Center
List<Moments> mu = new ArrayList<>(contours.size());
mu.add(1, Imgproc.moments(contours.get(1), false));
Utils.matToBitmap(hsv,Bitmap);
//...
And the lines with Moments brings me following error message:
No implementation found for double[] org.opencv.imgproc.Imgproc.moments_0(long, boolean) ( tried Java_org_opencv_imgproc_Imgproc_moments_10 and Java_org_opencv_imgproc_Imgproc_moments_10__JZ )
So if i jump to Imgproc.java then the method is red marked and following message popups by mouseover:
Cannot resolve corresponding JNI function Java_org_opencv_imgproc_Imgproc_moments_10
Reports native method declaration in Java where no corresponding JNI functions is found in the project.
Thanks for reading
Can anyone help me ?
Related
I'm working on android app, which determines which font is used on a text image. So I need to extract every character from image and don't know how to do it precisely. Furthermore, when I'm trying to process an image I have one result...but my classmate has different (for example, more or less noise). The problem with character detection is that:
1) it detects also some noise blobs on image and shows it in rectangles (I thought about detectMultiScale... but I have doubts about it, maybe there are easiest ways to detect characters)
2) it detects several contours of one character (for example inner and outer radius of letter "o")
And question for the future: I'm going to create a DB with images (for now just 3 fonts) of different letters of fonts and compare them with an image of letters from photo. Maybe someone could recommend a better way to do it.
So this is part of code with image processing(I'm still playing with values of blur, threshold and Canny... but there was no really positive result):
Imgproc.cvtColor(sImage, grayImage, Imgproc.COLOR_BGR2GRAY); //градации серого
Imgproc.GaussianBlur(grayImage,blurImage,new Size(5, 5),0); //размытие
Imgproc.adaptiveThreshold(blurImage, thresImage, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 101, 39);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.Canny(thresImage, binImage, 30, 10, 3, true); //контур
Imgproc.findContours(binImage, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
hierarchy.release();
Imgproc.drawContours(binImage, contours, -1, new Scalar(255, 255, 255));//, 2, 8, hierarchy, 0, new Point());
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());
//Processing on mMOP2f1 which is in type MatOfPoint2f
double approxDistance = Imgproc.arcLength(contour2f, true) * 0.02;
Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);
//Convert back to MatOfPoint
MatOfPoint points = new MatOfPoint(approxCurve.toArray());
// Get bounding rect of contour
Rect rect = Imgproc.boundingRect(points);
// draw enclosing rectangle (all same color, but you could use variable i to make them unique)
Imgproc.rectangle(binImage, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 255, 255), 5);
}
And screen (not actually with processing values from code, just one with better results):
Original:
(unfortunately, I can't add more than 2 links to show more examples)
There were situations, when picture from this screen looked pretty good, but another pictures looked like with shapeless blobs.
Your code is fine, you just need to make a minor tweaks to get it work properly.
Firstly, the image size is very large, you can safely reduce it to 20% of current size without suffering a major loss in accuracy. Due to larger image size all the functions would perform slower.
You dont need to perform adaptive threshold before Canny, canny works perfectly on gray-scale images as well, You need to adjust the params as:
Canny(img, threshold1=170, threshold2=250)
which yields an image as:
[Optional] If you want to de-noise the image then you can try with morphological operations like erode and dilate.
Now you are ready to find the contours. The mistake in your code was using Imgproc.RETR_TREE flag you need to use Imgproc.RETR_EXTERNAL flag to get only the outer contours and not the nested inner contours.
At this step you may have some unwanted small contours, which can be filtered as:
// ** Below code if for reference purposes only, consult OpenCV docs for proper API methods
int character_area_lower_thresh = 10;
for (Contour c:contours) {
if (Imgproc.contourArea(c) > character_area_lower_thresh) {
// Desired contour, do what ever you want to do
Rect r = Imgproc.boundingRect(c);
}
}
I'm trying to blur the faces of all people detected by the webcam.
The problem is that when the webcam detect a face the program shows the crop mat with the blur face.
I tried to put the blur face into the original mat but it doesn't work.
for(Rect rect : faces.toArray()){
Imgproc.rectangle(frame, rect.tl(), rect.br(), new Scalar(0,0,255),3);
Rect rectCrop = new Rect(rect.x, rect.y , rect.width, rect.height);
Mat imageROI = grayFrame.submat(rectCrop);
//frame is the original mat with the correct size
Imgproc.GaussianBlur(imageROI, frame, new Size(55, 55), 55);
}
No face detection:
With face detection:
use this constructor of Mat
Mat imageROI = new Mat(grayFrame,rectCrop);
instead of
Mat imageROI = grayFrame.submat(rectCrop);
The constructor gives you reference to the data matrix that is owned by grayFrame. so any modifications to submat will effect the bigmat.The submat gives copy of the grayFrame data matrix for the crop rectangle. So the modifications on the submat will not effect the bigmat.
I am trying to extract the title bar from the image below using opencv.
I am using the following code -
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat original = Imgcodecs.imread("D:/test_bg_extract.png", Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
Mat hsvMat = new Mat();
Imgproc.cvtColor(original, hsvMat, Imgproc.COLOR_BGR2HSV);
Mat dst = new Mat();
Core.inRange(hsvMat, new Scalar(23,231,205), new Scalar(23,231,205), dst);
I used a color picker to determine the HSV value of the title bar (from the hsvMat converted to display image). When the run the code to display the output, I see a blank screen. I can't tell what I am doing wrong. Am I picking the wrong HSV color? If I know the exact RGB code then should I even be converting image to HSV? (this however seems to be the standard method from many code examples on the internet).
Ok, I solved it using RGB based color, switching to BGR while specifying the color that I need. So this worked -
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat original = Imgcodecs.imread("D:/test_bg_extract.png", Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
Mat dst = new Mat();
Core.inRange(original, new Scalar(132,178,205), new Scalar(132,178,205), dst);
I want to get all the outer contours with RETR_EXTERNAL but for some weird reason openCV thinks that the image border is a contour too and therefore discards all inner contours. What exactly am I doing wrong here?
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.findContours(imageA, contours, hierarchy, Imgproc.RETR_EXTERNAL,
Imgproc.CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++) {
double[] c = hierarchy.get(0, i);
Rect rect = Imgproc.boundingRect(contours.get(i));
Core.rectangle(image, new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0), 3);
}
Input (imageA was processed to this before contour-finding):
Output:
EDIT:
Problem partially solved
Inverting the pixels so that black is the background and white the foreground helped with the image above image. However I still get inner contours on some images. Like this one:
Input
Output
Your input image isnt good enought o extract the contours you want to have.
Your input contours are these (part of your image):
each color is a single contour (and some of the white ones)
For the red contour I've drawn the bounding rectangle which is the same method that you used to display the contours. All the other colored contours aren't inside of the red contour, but just inside of the bounding rectangle, that's why they are found even though you selected to only find the outer contours.
What you really want is something like this:
but to get that result, your input image must have that lines of the ellipse connected, too!!
For your input image it will be very hard to extract those lines, without getting lines of the ground too, but an easy approach could be to use a couple of dilation operations followed by the same number of erosion operations on your input image, before extracting contours. This won't be stable for all setting though ;)
I am developing an Android app that calculates the sum of all points of the being-seen dominoes pieces -shown in picture- using OpenCV for Android.
The problem is, I can't find a way to filtering other contours and counting only dots I see in the dominoes, I tried to use Canny edge finding then use HoughCircles, but with no result, as I don't have an absolute top view of the rocks and HoughCircles detect perfect circles only :)
Here is my code:
public Mat onCameraFrame(Mat inputFrame) {
inputFrame.copyTo(mRgba);
Mat grey = new Mat();
// Make it greyscale
Imgproc.cvtColor(mRgba, grey, Imgproc.COLOR_RGBA2GRAY);
// init contours arraylist
List<MatOfPoint> contours = new ArrayList<MatOfPoint>(200);
//blur
Imgproc.GaussianBlur(grey, grey, new Size(9,9), 10);
Imgproc.threshold(grey, grey, 80, 150, Imgproc.THRESH_BINARY);
// because findContours modifies the image I back it up
Mat greyCopy = new Mat();
grey.copyTo(greyCopy);
Imgproc.findContours(greyCopy, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_NONE);
// Now I have my controus pefectly
MatOfPoint2f mMOP2f1 = new MatOfPoint2f();
//a list for only selected contours
List<MatOfPoint> SelectedContours = new ArrayList<MatOfPoint>(400);
for(int i=0;i<contours.size();i++)
{
if(here I should put a condition that distinguishes my spots, eg: if contour inside is black and is a black disk)
{
SelectedContours.add(contours.get(i));
}
}
Imgproc.drawContours(mRgba, SelectedContours, -1, new Scalar(255,0,0,255), 1);
return mRgba;
}
EDIT:
One unique feature of my contours after threshold is they're totally black from inside, is there anyway I could calculate the mean color/intensity for a given contour ?
There is a similiar problem and possible solution on SO, titled Detection of coins (and fit ellipses) on an image. Here you will find some recomendations about opencv's function fitEllipse.
You should take a look at this for more info on opencv's function fitEllipse.
Also, to detect only black elements in an image, you can use HSV color model, to find only black colors. You can find an explanation here.