Removing blobs from a binary image - opencv

I have a binary image which contain few blobs.
I want to remove blobs which are less than a certain area.
Can any one suggest me a way?
I am using Open-CV. i did dilation and erosion to get those blobs. so i need something different to remove the reaming blobs which are less than a certain area.

You can do something like this:
// your input binary image
// assuming that blob pixels have positive values, zero otherwise
Mat binary_image;
// threashold specifying minimum area of a blob
double threshold = 100;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
vector<int> small_blobs;
double contour_area;
Mat temp_image;
// find all contours in the binary image
binary_image.copyTo(temp_image);
findContours(temp_image, contours, hierarchy, CV_RETR_CCOMP,
CV_CHAIN_APPROX_SIMPLE);
// Find indices of contours whose area is less than `threshold`
if ( !contours_all.empty()) {
for (size_t i=0; i<contours.size(); ++i) {
contour_area = contourArea(contours_all[i]) ;
if ( contour_area < threshold)
small_blobs.push_back(i);
}
}
// fill-in all small contours with zeros
for (size_t i=0; i < small_blobs.size(); ++i) {
drawContours(binary_image, contours, small_blobs[i], cv::Scalar(0),
CV_FILLED, 8);
}

//src_gray is your image that we threshold
threshold(src_gray, threshold_output, NULL, 255, THRESH_OTSU);
/// Find contours
findContours(threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
/// Approximate contours
vector<Rect> boundRect(contours.size());
for (unsigned int i = 0; i < contours.size(); i++)
{ //identify bounding box
boundRect[i] = boundingRect(contours[i]);
}
for (unsigned int i = 0; i < contours.size(); i++)
{
if ((boundRect[i].area() < //enter your area here))
{
src_gray(boundRect[i])=//set it to whatever value you want;
}
}
Well give this a try...

Related

object detection of various shapes in opencv

I have an image and want to detect various objects at a time using opencv methods.
I have tried detecting one object using contouring and using the area to filter other counters. But I need to detect other objects too but they vary in area and length.
Can anyone help me to use any methods for detecting it.
This is the original image:
this is the code that I have tried for detection:
int main()
{
Mat msrc = imread("Task6_Resources/Scratch.jpg", 1);
Mat src = imread("Task6_Resources/Scratch.jpg", 0);
Mat imgblur;
GaussianBlur(src, imgblur, Size(13,13), 0);
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();
clahe->setClipLimit(8);
cv::Mat gcimg;
clahe->apply(imgblur, gcimg);
Mat thresh;
threshold(gcimg, thresh, 55, 255, THRESH_BINARY_INV);
Mat th_mina = minareafilter(thresh, 195); //function used to filter small and large blobs
Mat th_maxa = maxareafilter(th_mina, 393);
Mat imdilate;
dilate(th_maxa, imdilate, getStructuringElement(MORPH_RECT, Size(3, 1)), Point(-1, -1), 7);
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(imdilate, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
cout << "Number of contours" << contours.size() << endl;
//Largest contour according to area
for (int i = 0; i < contours.size(); i++){
double a = contourArea(contours[i], false);
if (a > largest_area) {
largest_area = a;
largest_contour_index = i;
bounding_rect = boundingRect(contours[i]);
}
}
for (int c = 0; c < contours.size(); c++){
printf(" * Contour[%d] Area OpenCV: %.2f - Length: %.2f \n",
c,contourArea(contours[c]), arcLength(contours[c], true));
}
rectangle(msrc, bounding_rect, Scalar(0, 255, 0), 2, 8, 0);
imshow("largest contour", msrc);
waitKey(0);
destroyAllWindows();
return 0;
}
This is the image on which I am applying contouring
After the code I am able to detect the green box using largest area in contouring, but I need to detect those red boxes too. (only the region of red boxes)
The problem is here I cannot apply again area parameter to filter the contours as some other contours have same area as the resultant contour.
The image result required:

find trapezoid's 4 points for wraping (rectangle )

I need to find trapezoid's 4 points. I tried to use "ret" but only 2 points, seems just 1point is good.
find biggest rectangle result
int main(int argc, char** argv)
{
Mat src = imread("IMG_20160708_1338252.jpg");
imshow("source", src);
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
Mat thr;
cvtColor(src, thr, COLOR_BGR2GRAY); //Convert to gray
threshold(thr, thr, 125, 255, THRESH_BINARY); //Threshold the gray
vector<vector<Point> > contours; // Vector for storing contours
findContours(thr, contours, RETR_CCOMP, CHAIN_APPROX_SIMPLE); // Find the contours in the image
for (size_t i = 0; i < contours.size(); i++) // iterate through each contour.
{
double area = contourArea(contours[i]); // Find the area of contour
//src면적이랑 area가 같으면 제외
//if (src.size().area != area) {
if (area > largest_area)
{
largest_area = area;
largest_contour_index = i; //Store the index of largest contour
bounding_rect = boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
}
//}
}
printf("top%d,%d\n", bounding_rect.tl().x, bounding_rect.tl().y);
printf("bottom%d,%d\n\n", bounding_rect.br().x, bounding_rect.br().y);
printf("top%d,%d\n", bounding_rect.x, bounding_rect.y);
printf("%d,%d\n", bounding_rect.x, bounding_rect.y+ bounding_rect.height);
printf("bottom%d,%d\n", bounding_rect.x + bounding_rect.width, bounding_rect.y);
printf("%d,%d\n\n", bounding_rect.x+ bounding_rect.width, bounding_rect.y+ bounding_rect.height);
//printf("bottom%d,%d\n", bounding_rect.br().x, bounding_rect.br().y);
//contours[largest_contour_index];//가장큰 사각형
//contours[largest_contour_index][0].x; contours[largest_contour_index][0].y;
printf("1-%d,", contours[largest_contour_index]);
printf("1-%d\n", contours[largest_contour_index][0].y);
printf("2-%d,", contours[largest_contour_index][1].x);
printf("2-%d\n", contours[largest_contour_index][1].y);
printf("3-%d,", contours[largest_contour_index][2].x);
printf("3-%d\n", contours[largest_contour_index][2].y);
printf("4-%d,", contours[largest_contour_index][3].x);
printf("4-%d\n", contours[largest_contour_index][3].y);
//printf("1%d,", contours[0][largest_contour_index].x);
drawContours(src, contours, largest_contour_index, Scalar(0, 255, 0), 2); // Draw the largest contour using previously stored index.
imshow("result", src);
waitKey();
return 0;
}
How can I find biggest rectangle?

OpenCV: Retrieving color of the center of a contour

Im trying to detect the colour of a set of shapes in a black image using OpenCV, for which I use Canny detection. However the color output always comes back as black.
std::vector<std::pair<cv::Point, cv::Vec3b> > Asteroids::DetectPoints(const cv::Mat &image)
{
cv::Mat imageGray;
cv::cvtColor( image, imageGray, CV_BGR2GRAY );
cv::threshold(imageGray, imageGray, 1, 255, cv::THRESH_BINARY);
cv::Mat canny_output;
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
int thresh = 10;
// Detect edges using canny
cv::Canny( imageGray, canny_output, thresh, thresh*2, 3 );
// Find contours
cv::findContours( canny_output, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cv::Point(0, 0) );
std::vector<std::pair<cv::Point, cv::Vec3b> > points;
for(unsigned int i = 0; i < contours.size(); i++ )
{
cv::Rect rect = cv::boundingRect(contours[i]);
std::pair<cv::Point, cv::Vec3b> posColor;
posColor.first = cv::Point( rect.tl().x + (rect.size().width / 2), rect.tl().y + (rect.size().height / 2));
posColor.second = image.at<cv::Vec3b>( posColor.first.x, posColor.first.y );
//Dont add teh entry to the list if one with the same color and position is already pressent,
//The contour detection sometimes returns duplicates
bool isInList = false;
for(unsigned int j = 0; j < points.size(); j++)
if(points[j].first == posColor.first && points[j].second == posColor.second)
isInList = true;
if(!isInList)
points.push_back( posColor );
}
return points;
}
I know it has to be an issue with the positions or something along those lines, but I cant figure out what
I might be wrong, but off the top of my head :
Shouldn't this read
posColor.second = image.at<cv::Vec3b>(posColor.first.y, posColor.first.x);
and not the other way around like you did it ?
Matrix notation, not cartesian notation ?

How can i get perfect edge detection of document in IOS?

First of all sorry if question was asked. I am working on an app that can detect the corner of a document. I am right now using openCV to detect edge. I have achieved this using openCV but I am not getting the perfect result.
I have also tried the BradLarson GPUImage but I am able how to start with this.
My code that detect the corner of the document but not a perfect result.
void find_squares(Mat& image, cv::vector<cv::vector<cv::Point>>&squares)
{
// blur will enhance edge detection
Mat blurred(image);
//cv::resize(image, image, cvSize(0.25, 0.25));
Mat gray0(blurred.size(), CV_8U), gray;
//medianBlur(image, blurred, 9); //default 9;
GaussianBlur(image, blurred, cvSize(9, 9), 2.0,2.0);
vector<vector<cv::Point> > contours;
// find squares in every color plane of the image
for (int c = 0; c < 3; c++)
{
int ch[] = {c, 0};
mixChannels(&blurred, 1, &gray0, 1, ch, 1);
// try several threshold levels
const int threshold_level = 4;
for (int l = 0; l < threshold_level; l++)
{
// Use Canny instead of zero threshold level!
// Canny helps to catch squares with gradient shading
if (l == 0)
{
Canny(gray0, gray, 10, 20, 3); //
// Dilate helps to remove potential holes between edge segments
dilate(gray, gray, Mat(), cv::Point(-1,-1));
}
else
{
gray = gray0 >= (l+1) * 255 / threshold_level;
}
// Find contours and store them in a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
// Test contours
vector<cv::Point> approx;
for (size_t i = 0; i < contours.size(); i++)
{
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if (approx.size() == 4 &&
fabs(contourArea(Mat(approx))) > 1000 &&
isContourConvex(Mat(approx)))
{
double maxCosine = 0;
for (int j = 2; j < 5; j++)
{
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
if (maxCosine < 0.3)
squares.push_back(approx);
}
}
}
}
}
So my questions are:
1) is there any other library that can do this.
2) is there any problem in above code? Should I add some image processing before detection?
3) Can BradLarson GPUImage do this? And if it can then are there sources of sample code for edge detection?

OpenCV squares: filtering output

Here is the out put of square-detection example my problem is filter this squares
first problem is its drawing one than more lines for same area;
second one is i just need to detect object not all image.
The other problem is i have to take just biggest object except all image.
Here is a code for detection:
static void findSquares( const Mat& image, vector >& squares ){
squares.clear();
Mat pyr, timg, gray0(image.size(), CV_8U), gray;
// down-scale and upscale the image to filter out the noise
pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
pyrUp(pyr, timg, image.size());
vector<vector<Point> > contours;
// find squares in every color plane of the image
for( int c = 0; c < 3; c++ )
{
int ch[] = {c, 0};
mixChannels(&timg, 1, &gray0, 1, ch, 1);
// try several threshold levels
for( int l = 0; l < N; l++ )
{
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if( l == 0 )
{
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
Canny(gray0, gray, 0, thresh, 5);
// dilate canny output to remove potential
// holes between edge segments
dilate(gray, gray, Mat(), Point(-1,-1));
}
else
{
// apply threshold if l!=0:
gray = gray0 >= (l+1)*255/N;
}
// find contours and store them all as a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
// test each contour
for( size_t i = 0; i < contours.size(); i++ )
{
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
if( approx.size() == 4 &&
fabs(contourArea(Mat(approx))) > 1000 &&
isContourConvex(Mat(approx)) )
{
double maxCosine = 0;
for( int j = 2; j < 5; j++ )
{
// find the maximum cosine of the angle between joint edges
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
if( maxCosine < 0.3 )
squares.push_back(approx);
}
}
}
}
}
You need to take a look at the flags for findContours(). You can set a flag called CV_RETR_EXTERNAL which will return only the outer-most contour (all contours inside of it are thrown away). This will probably return the entire frame, so you'll need to narrow down the search so that it doesnt check your frame boundaries. Use the function copyMakeBorder() to accomplish this. I would also recommend removing your dilate function as it is probably causing duplicate contours on either side of a line (you might not even need the border if you remove the dilate). Here is my output:

Resources