Reputation: 1
I am using OpenCV4Android version 2.4.11 and I am trying to detect the rectangles in frames retrieved from Camera. I referred to some questions in this website and they were so helpful. but the issue i am facing currently is when i try to detect an object with light color in the middle as shown in the original image below the detection algorithm in this case does not detect the object as whole, rather it detects the dark parts of it as shown in image in the section titled "processed" below.
the code posted below indicates the steps i followed and the threshold values i used to detect the objects in the frames.
please let me know why the object as a whole is not getting detected and what can i do to detect the whole object not only parts of it
code:
//step 1
this.mMatGray = new Mat();
Imgproc.cvtColor(this.mMatInputFrame, this.mMatGray, Imgproc.COLOR_BGR2GRAY);
//step 2
this.mMatEdges = new Mat();
Imgproc.blur(this.mMatGray, this.mMatEdges, new Size(7, 7));//7,7
//step 3
Imgproc.Canny(this.mMatEdges, this.mMatEdges, 128, 128*2, 5, true);//..,..,2,900,7,true
//step 4
dilated = new Mat();
Mat dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(3, 3));
Imgproc.dilate(mMatEdges, dilated, dilateElement);
ArrayList<MatOfPoint> contours = new ArrayList<>();
hierachy = new Mat();
Imgproc.findContours(dilated, contours, hierachy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint2f approxCurve = new MatOfPoint2f();
if (contours.size() > 0) {
for (int i = 0; i < contours.size(); i++) {
MatOfPoint2f contour2f = new MatOfPoint2f(contours.get(i).toArray());
double approxDistance = Imgproc.arcLength(contour2f, true) * .02;//.02
Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);
MatOfPoint points = new MatOfPoint(approxCurve.toArray());
if (points.total() >= 4 && Imgproc.isContourConvex(points) && Math.abs(Imgproc.contourArea(points)) >= 40000 && Math.abs(Imgproc.contourArea(points)) <= 150000) {
Rect boundingRect = Imgproc.boundingRect(points);
RotatedRect minAreaRect = Imgproc.minAreaRect(contour2f);
Point[] rectPoints = new Point[4];
minAreaRect.points(rectPoints);
Rect minAreaAsRect = minAreaRect.boundingRect();
//to draw the minAreaRect
for( int j = 0; j < 4; j++ ) {
Core.line(mMatInputFrame, rectPoints[j], rectPoints[(j+1)%4], new Scalar(255,0,0));
}
Core.putText(mMatInputFrame, "MinAreaRect", new Point(10, 30), 1,1 , new Scalar(255,0,0),2);
Core.putText(mMatInputFrame, "Width: " + minAreaAsRect.width , new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-100), 1,1 , new Scalar(255,0,0),2);
Core.putText(mMatInputFrame, "Height: " + minAreaAsRect.height, new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-80), 1,1 , new Scalar(255,0,0),2);
Core.putText(mMatInputFrame, "Area: " + minAreaAsRect.area(), new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-60), 1,1 , new Scalar(255,0,0),2);
//drawing the contour
Imgproc.drawContours(mMatInputFrame, contours, i, new Scalar(0,0,0),2);
//drawing the boundingRect
Core.rectangle(mMatInputFrame, boundingRect.tl(), boundingRect.br(), new Scalar(0, 255, 0), 1, 1, 0);
Core.putText(mMatInputFrame, "BoundingRect", new Point(10, 60), 1,1 , new Scalar(0,255,0),2);
Core.putText(mMatInputFrame, "Width: " + boundingRect.width , new Point(boundingRect.br().x-100, boundingRect.tl().y-100), 1,1 , new Scalar(0,255,0),2);
Core.putText(mMatInputFrame, "Height: " + boundingRect.height, new Point(boundingRect.br().x-100, boundingRect.tl().y-80), 1,1 , new Scalar(0,255,0),2);
Core.putText(mMatInputFrame, "Area: " + Imgproc.contourArea(points), new Point(boundingRect.br().x-100, boundingRect.tl().y-60), 1,1 , new Scalar(0,255,0),2);
}
}
}
original image:
processed image:
Upvotes: 2
Views: 865
Reputation: 1090
I have implemented in c++. API's are same so you can easily port for android. I have used Opencv 2.4.8
. Please check the implementation. Hope the code says what is done:
#include <iostream>
#include <string>
#include "opencv/highgui.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
using namespace std;
using namespace cv;
Mat GetKernel(int erosion_size)
{
Mat element = getStructuringElement(cv::MORPH_CROSS,
cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1),
cv::Point(erosion_size, erosion_size) );
return element;
}
int main()
{
Mat img = imread("C:/Users/dell2/Desktop/j6B3A.png",0);//loading gray scale image
Mat imgC = imread("C:/Users/dell2/Desktop/j6B3A.png",1);
GaussianBlur(img,img,Size(7,7),1.5,1.5);
Mat dimg;
adaptiveThreshold(img,dimg,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,17,1);
dilate(dimg,img,GetKernel(2));
erode(img,dimg,GetKernel(2));
erode(dimg,img,GetKernel(1));
dimg = img;
//*
vector<vector<Point>> contours; // Vector for storing contour
vector<Vec4i> hierarchy;
findContours( dimg, contours, hierarchy,CV_RETR_TREE , CV_CHAIN_APPROX_NONE ); // Find the contours in the image
double largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
for( int i = 0; i< contours.size(); i++ ) // iterate through each contour.
{
double a=contourArea( contours[i],false); // Find the area of contour
if(a>largest_area){
largest_area=a;
largest_contour_index=i; //Store the index of largest contour
bounding_rect=boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
}
}
drawContours( imgC, contours, largest_contour_index, Scalar(255,0,0), 2, 8, hierarchy, 0, Point() );
rectangle(imgC, bounding_rect, Scalar(0,255,0),2, 8,0);
/**/
//imshow("display",dimg);
imshow("display2",imgC);
waitKey(0);
return 0;
}
Output produced:
You can fine tune the threshold if necessary.
Upvotes: 2