I want to find the convex and get convexity defects for the biggest contour .Here my code for finding the biggest contour.I use opencv for android.Can someone guild me please.
Imgproc.cvtColor (inputFrame.rgba(), mIntermediateMat, Imgproc.COLOR_RGB2YCrCb, 4);
Core.inRange(mIntermediateMat, new Scalar(1, 133, 77), new Scalar(255, 173, 127), mGray);
Imgproc.erode(mGray,mGray, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(4,4)));
Imgproc.dilate(mGray, mGray, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(4, 4)));
Imgproc.blur(mGray, mGray, new Size(3.0, 3.0));
Imgproc.adaptiveThreshold(mGray, mcontour, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C,Imgproc.THRESH_BINARY_INV, 3, 1);
mRgba = inputFrame.rgba();
maxContourArea=0;
contours= new ArrayList<MatOfPoint>();
Imgproc.findContours(mcontour, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
for (int idx = 0; idx < contours.size(); idx++)
{
contour = contours.get(idx);
double contourarea = Imgproc.contourArea(contour);
if (contourarea > maxContourArea )
{
maxContourArea = contourarea;
maxAreaIdx = idx;
}
}
if(maxContourArea>1000)
{
Imgproc.drawContours ( mRgba, contours, maxAreaIdx, new Scalar(120,120,120),2);
}
contours.clear();
there are functions about
cv::convexityDefects() Finds the convexity defects of a contour
cv::isContourConvex() Tests a contour convexity
http://docs.opencv.org/3.0.0/d3/dc0/group__imgproc__shape.html
Related
I'm trying to only detect, draw & fill/color the battery black while filling everything else white, but I'm getting other lines from the background as well. How do i go about fixing this?
Note: I cannot change the background of the input image.
Below is the output of an image i got after drawing the contours of everything that's black using the following code:
if(getIntent().hasExtra("byteArray")) {
b = BitmapFactory.decodeByteArray(getIntent().getByteArrayExtra("byteArray"),0,getIntent().getByteArrayExtra("byteArray").length);
contours = new ArrayList<>();
srcMat= new Mat();
gray = new Mat();
matHSV = new Mat();
Utils.bitmapToMat(b,srcMat);
Imgproc.cvtColor(srcMat, gray, Imgproc.COLOR_RGBA2GRAY);
Imgproc.Canny(gray, gray, 20, 20*3, 3, true);
Mat hierarchy = new Mat();
Imgproc.findContours(gray,contours,hierarchy,Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
for (int contourIdx = 0; contourIdx < contours.size(); contourIdx++) {
Imgproc.drawContours(srcMat, contours, contourIdx, new Scalar(0, 0, 255), -1);
}
mask = new Mat(new Size(srcMat.cols(), srcMat.rows() ), CvType.CV_8UC1);
mask.setTo(new Scalar(255));
black = new Scalar(0,0,0);
Imgproc.drawContours(mask, contours, -1, black, 10);
for (MatOfPoint contour: contours) {
Imgproc.fillPoly(mask, Arrays.asList(contour), black);
}
Mat masked = new Mat();
srcMat.copyTo(masked, mask);
Utils.matToBitmap(mask, b);
imgR.setImageBitmap(b);
}
Output:
Input:
I am new to image processing and I cant get fillPoly() working. Also, drawContours() is leaving some spaces while drawing contours. I am working on Android and most of the references that are given on internet are of Python, Matlab or C++
sSize5 = new Size(5, 5);
mIntermediateMat = new Mat();
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.contours_in_contours_red);
Mat rgba = new Mat(bmp.getHeight(), bmp.getWidth(), CvType.CV_8UC1);
Utils.bitmapToMat(bmp, rgba);
Mat greyInnerWindow;
greyInnerWindow = new Mat();
Mat mRgba = new Mat();
Imgproc.cvtColor(rgba, greyInnerWindow, Imgproc.COLOR_RGBA2GRAY);
Imgproc.GaussianBlur(greyInnerWindow, greyInnerWindow, sSize5, 2, 2);
Imgproc.Canny(greyInnerWindow, mIntermediateMat, 5, 35);
Imgproc.cvtColor(mIntermediateMat, mRgba, Imgproc.COLOR_GRAY2BGRA, 4);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(mIntermediateMat, contours, mHierarchy, Imgproc.RETR_EXTERNAL,
Imgproc.CHAIN_APPROX_SIMPLE);
for( int i = 0; i< contours.size(); i++ )
{
Imgproc.drawContours(rgba, contours, i, new Scalar(0, 255, 0), -1);
Imgproc.fillPoly(rgba, contours, new Scalar(0,255,0));
}
Bitmap resultBitmap = Bitmap.createBitmap(rgba.cols(), rgba.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(rgba, resultBitmap);
imageView.setImageBitmap(resultBitmap);
I am trying to draw the contour of every element in a picture with separated musical notations.
This is the code that I am running in android/java:
public static Bitmap findNotationContours(Bitmap inputImage) {
Mat inputImageMat = new Mat();
Utils.bitmapToMat(inputImage, inputImageMat);
Imgproc.cvtColor(inputImageMat, inputImageMat, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(inputImageMat, inputImageMat, new Size(5, 5), 0);
Imgproc.adaptiveThreshold(inputImageMat, inputImageMat, 255, 1, 1, 11, 2);
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(inputImageMat, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
int contourColor = android.R.color.holo_red_dark;
Scalar contourScalar = new Scalar(Color.red(contourColor), Color.green(contourColor), Color.blue(contourColor));
for (int i = 0; i < contours.size(); i++) {
Rect rect = Imgproc.boundingRect(contours.get(i));
Imgproc.rectangle(inputImageMat,
new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height),
contourScalar, 3);
}
Utils.matToBitmap(inputImageMat, inputImage);
return inputImage;
}
The result I am getting is:
If you zoom in enough you can see that the contour for the notations are there, but I need to keep the original picture with just a rectangle contour around each of them, so I can save those as a pattern.
Can you please tell me what I am doing wrong?
With the crucial information from #Dan MaĊĦek the problem was fixed, I will add the revised code that needs no explanation, just that we keep a Mat with the initial 3-channel image which we use to draw the contour rectangles on.
public static Bitmap findNotationContours(Bitmap inputImage) {
Mat inputImageMat = new Mat();
Mat resultImageMat = new Mat();
Utils.bitmapToMat(inputImage, inputImageMat);
Utils.bitmapToMat(inputImage, resultImageMat);
Imgproc.cvtColor(inputImageMat, inputImageMat, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(inputImageMat, inputImageMat, new Size(5, 5), 0);
Imgproc.adaptiveThreshold(inputImageMat, inputImageMat, 255, 1, 1, 11, 2);
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(inputImageMat, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Scalar contourScalar = new Scalar(255,0,0);
for (int i = 0; i < contours.size(); i++) {
Rect rect = Imgproc.boundingRect(contours.get(i));
Imgproc.rectangle(resultImageMat,
new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height),
contourScalar, 3);
Log.i("contour", "contour" + i + " x:" + rect.x + " y:" + rect.y);
}
Utils.matToBitmap(resultImageMat, inputImage);
return inputImage;
}
final result
Currently I'm developing an app that will detect colored circles. I'm trying to do this by following this tutorial, where guy detects red circles on image with Python. I've written the same code, just for Java.
Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(),
CvType.CV_8UC3);
Mat hsv_image = new Mat();
Utils.bitmapToMat(bitmap, mat);
Imgproc.cvtColor(mat, hsv_image, Imgproc.COLOR_BGR2HSV);
Mat lower_red_hue_range = new Mat();
Mat upper_red_hue_range = new Mat();
Core.inRange(hsv_image, new Scalar(0, 100, 100), new Scalar(10, 255, 255), lower_red_hue_range);
Core.inRange(hsv_image, new Scalar(160, 100, 100), new Scalar(179, 255, 255), upper_red_hue_range);
Utils.matToBitmap(hsv_image, bitmap);
mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(mutableBitmap);
Image I use is identical to one from tutorial:
This is image with applied BGR2HSV:
When I execute the code using lower red hue range, it detects the blue circle. When I use upper red hue range it gives me black bmp(doesn't detect anything). How can it be? What am I doing wrong? This is literally copy moved from python to Java. Why's the result different then?
Thanks in advance.
Your mat is of CvType.CV_8UC1 image, i.e. you are working on a grayscale image. Try with CvType.CV_8UC3
Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC3);
hsv_image should look like this:
How to select a custom range:
You may want to detect a green circle.
Well, in HSV, tipically the range is:
H in [0,360]
S,V in [0,100]
However, for CV_8UC3 images, each component H,S,V can be represented by only 256 values at most, since it's stored in 1 byte. So, in OpenCV, the ranges H,S,V for CV_8UC3 are:
H in [0,180] <- halved to fit in the range
S,V in [0,255] <- stretched to fit the range
So to switch from typical range to OpenCV range you need to:
opencv_H = typical_H / 2;
opencv_S = typical_S * 2.55;
opencv_V = typical_V * 2.55;
So, green colors are around the value of hue of 120. The hue can have a value in the interval [0,360].
However, for Mat3b HSV images, the range for H is in [0,180], i.e. is halved so it can fit in a 8 bit representation with at most 256 possible values.
So, you want the H value to be around 120 / 2 = 60, say from 50 to 70.
You also set a minimum value for S,V to 100 in order to prevent very dark (almost black) colors.
Mat green_hue_range
inRange(hsv_image, cv::Scalar(50, 100, 100), cv::Scalar(70, 255, 255), green_hue_range);
use the following code and pass color to Blob detector and then pass an image to the detector
private Scalar converScalarRgba2HSV(Scalar rgba) {
Mat pointMatHsv= new Mat();
Mat pointMatRgba = new Mat(1, 1, CvType.CV_8UC3, rgba);
Imgproc.cvtColor(pointMatRgba,pointMatHsv, Imgproc.COLOR_RGB2HSV_FULL, 4);
return new Scalar(pointMatHsv.get(0, 0));}
// Blob Detector
public class ColorBlobDetector {
// Lower and Upper bounds for range checking in HSV color space
private Scalar mLowerBound = new Scalar(0);
private Scalar mUpperBound = new Scalar(0);
// Minimum contour area in percent for contours filtering
private static double mMinContourArea = 0.1;
// Color radius for range checking in HSV color space
private Scalar mColorRadius = new Scalar(25,50,50,0);
private Mat mSpectrum = new Mat();
private List<MatOfPoint> mContours = new ArrayList<MatOfPoint>();
Mat mPyrDownMat = new Mat();
Mat mHsvMat = new Mat();
Mat mMask = new Mat();
Mat mDilatedMask = new Mat();
Mat mHierarchy = new Mat();
public void setColorRadius(Scalar radius) {
mColorRadius = radius;
}
public void setHsvColor(Scalar hsvColor) {
double minH = (hsvColor.val[0] >= mColorRadius.val[0]) ? hsvColor.val[0]-mColorRadius.val[0] : 0;
double maxH = (hsvColor.val[0]+mColorRadius.val[0] <= 255) ? hsvColor.val[0]+mColorRadius.val[0] : 255;
mLowerBound.val[0] = minH;
mUpperBound.val[0] = maxH;
mLowerBound.val[1] = hsvColor.val[1] - mColorRadius.val[1];
mUpperBound.val[1] = hsvColor.val[1] + mColorRadius.val[1];
mLowerBound.val[2] = hsvColor.val[2] - mColorRadius.val[2];
mUpperBound.val[2] = hsvColor.val[2] + mColorRadius.val[2];
mLowerBound.val[3] = 0;
mUpperBound.val[3] = 255;
Mat spectrumHsv = new Mat(1, (int)(maxH-minH), CvType.CV_8UC3);
for (int j = 0; j < maxH-minH; j++) {
byte[] tmp = {(byte)(minH+j), (byte)255, (byte)255};
spectrumHsv.put(0, j, tmp);
}
Imgproc.cvtColor(spectrumHsv, mSpectrum, Imgproc.COLOR_HSV2RGB_FULL, 4);
}
public Mat getSpectrum() {
return mSpectrum;
}
public void setMinContourArea(double area) {
mMinContourArea = area;
}
public void process(Mat rgbaImage) {
Imgproc.pyrDown(rgbaImage, mPyrDownMat);
Imgproc.pyrDown(mPyrDownMat, mPyrDownMat);
Imgproc.cvtColor(mPyrDownMat, mHsvMat, Imgproc.COLOR_RGB2HSV_FULL);
Core.inRange(mHsvMat, mLowerBound, mUpperBound, mMask);
Imgproc.dilate(mMask, mDilatedMask, new Mat());
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(mDilatedMask, contours, mHierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
// Find max contour area
double maxArea = 0;
Iterator<MatOfPoint> each = contours.iterator();
while (each.hasNext()) {
MatOfPoint wrapper = each.next();
double area = Imgproc.contourArea(wrapper);
if (area > maxArea)
maxArea = area;
}
// Filter contours by area and resize to fit the original image size
mContours.clear();
each = contours.iterator();
while (each.hasNext()) {
MatOfPoint contour = each.next();
if (Imgproc.contourArea(contour) > mMinContourArea*maxArea) {
Core.multiply(contour, new Scalar(4,4), contour);
mContours.add(contour);
}
}
}
public List<MatOfPoint> getContours() {
return mContours;
}}
now set detector
public void initDetector() {
mDetector = new ColorBlobDetector();
mSpectrum = new Mat();
mBlobColorRgba = new Scalar(255);
mBlobColorHsv = new Scalar(255);
SPECTRUM_SIZE = new org.opencv.core.Size(500, 64);
CONTOUR_COLOR = new Scalar(0, 255, 0, 255);
mDetector.setHsvColor(converScalarRgba2HSV(new Scalar(0,255,255,255)));
Imgproc.resize(mDetector.getSpectrum(), mSpectrum, SPECTRUM_SIZE, 0, 0, Imgproc.INTER_LINEAR_EXACT);
mIsColorSelected = true;
}
now pass an image to a detector object
Mat mRgba = new Mat(inputFrame.height(), inputFrame.width(), CvType.CV_8UC4);
mRgba = inputFrame;
mDetector.process(mRgba);
List<MatOfPoint> contours = mDetector.getContours();
Log.e(TAG, "Contours count: " + contours.size());
drawContours(mRgba, contours, -1, CONTOUR_COLOR);
return mRgba;
Happy Codeing !!!
I am trying to recognize pedestrian traffic signal.I am converting the image to HSV color space, then applying in-range function to get only green lights.Here is my original image
This is my code..
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully...................");
Mat img = null;
try {
img = Utils.loadResource(getBaseContext(), R.drawable.glarrygreen, Highgui.CV_LOAD_IMAGE_COLOR);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Mat mHSV = new Mat();
Mat mRgba2 = new Mat();
Mat mHSVThreshed = new Mat();
Imgproc.cvtColor(img, mHSV, Imgproc.COLOR_BGR2HSV, 3);
//This works for red lights
Core.inRange(mHSV, new Scalar(0, 64, 200), new Scalar(69, 255, 255), mHSVThreshed);
//this works for green lights
Core.inRange(mHSV, new Scalar(85, 64, 200), new Scalar(170, 255, 255),
mHSVThreshed);
List < MatOfPoint > contours = new ArrayList < MatOfPoint > ();
Mat hierarchy = new Mat();
Imgproc.findContours(mRgba2, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double maxArea = -1;
int maxAreaIdx = -1;
for (int idx = 0; idx < contours.size(); idx++) {
Mat contour = contours.get(idx);
double contourarea = Imgproc.contourArea(contour);
if (contourarea > maxArea) {
maxArea = contourarea;
maxAreaIdx = idx;
}
}
Imgproc.cvtColor(mHSVThreshed, img, Imgproc.COLOR_GRAY2BGR, 0);
Imgproc.cvtColor(img, mRgba2, Imgproc.COLOR_BGR2RGBA, 0);
Bitmap bmp = Bitmap.createBitmap(img.cols(), img.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba2, bmp);
}
}
}
This is my output image
Now I need to filter out other green signals in the scene.How do I do this?How do I get the most prominent green signal in the scene.
EDIT 1:
I am trying to use findCountours() method, get list of contours ,iterate through the results and get the largest, then display only the largest contour.How to remove smaller contours?
You can try to filter your binary image with a non-maxima suppression algorithm.
Here is a Java Demo of non-max suppression.
Note that NMS algorithm can be coded using morphological function (Erosion and Dilatation).
EDIT it seems that opencv already has a NMS function with the following prototype:
void nonMaximaSuppression(const Mat& src, const int sz, Mat& dst, const Mat mask)
EDIT2 From opencv doc: For every possible (sz x sz) region within src, an element is a local maxima of src iff it is strictly greater than all other elements of windows which intersect the given element.
Try with 50x50 patch (sz := 50)
FYI The method is derived from the following paper: A. Neubeck and L. Van Gool. "Efficient Non-Maximum Suppression," ICPR 2006
I finally got this working by using findCountours() and drawContours() methods,
This is how it works,
Imgproc.GaussianBlur(mHSVThreshed, mHSVThreshed, new Size(5, 5), 5);
Imgproc.findContours(mHSVThreshed, contours,newcont, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double maxArea = -1;
int maxAreaIdx = -1;
for (int idx = 0; idx < contours.size(); idx++) {
Mat contour = contours.get(idx);
double contourarea = Imgproc.contourArea(contour);
if (contourarea > maxArea) {
maxArea = contourarea;
maxAreaIdx = idx;
}
}
Imgproc.drawContours(img, contours, maxAreaIdx, new Scalar(120, 255, 120), 1);
Bitmap bmp = Bitmap.createBitmap(img.cols(), img.rows(), Bitmap.Config.ARGB_8888);
Scalar c = new Scalar(255, 0, 0, 255);
Core.putText(img, VAL, new Point(100,100), 3, 1, c, 2);
Imgproc.erode(mHSVThreshed, mHSVThreshed, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1.5,1.5)));
Utils.matToBitmap(img, bmp);