I am using opencv blob detection function to detect black dots but it cause slow speed and high cpu consumption. Is there more effective way to detect those black dots ? and Blob detection sometimes not detecting some black dots
This is my example image
This is my existing code
SimpleBlobDetector::Params params;
params.minThreshold = 50;
params.maxThreshold = 200;
params.filterByArea = true;
params.minArea = 500;
params.filterByCircularity = true;
params.minCircularity = 0.1;
std::vector<KeyPoint> keypoints;
Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);
detector->detect( im, keypoints);
Mat im_with_keypoints;
drawKeypoints( im, keypoints, im_with_keypoints, Scalar(0,0,255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS );
These are the black dots try to detect
1- To be able to increase the speed during SimpleBlobDetector , you can resize your input source dividing by 2 or more. This will still help to find the blobs and also will increase the speed.
2- On the other hand, for precise solution you can detect each contour and draw circle around them. You can filter the circle by using the radius and also you can enter the inside of circle to count the pixel, to filter the contour size etc. You can go on with morphological functions to achieve the task.
Here is the code for guideline and output:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
RNG rng(12345);
int main()
{
Mat img = imread("/ur/img/directory/image.png",0);
imshow("Input",img);
medianBlur(img,img,5);
Mat canny_output;
Canny( img, canny_output, 145, 145*3 );
vector<vector<Point> > contours;
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
vector<vector<Point> > contours_poly( contours.size() );
vector<Point2f>centers( contours.size() );
vector<float>radius( contours.size() );
for( size_t i = 0; i < contours.size(); i++ )
{
approxPolyDP( contours[i], contours_poly[i], 3, true );
minEnclosingCircle( contours_poly[i], centers[i], radius[i] );
}
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( 0,255,255);
drawContours( drawing, contours_poly, (int)i, color );
if((int)radius[i]>0 && (int)radius[i]<100)
circle( img, centers[i], (int)radius[i], color, 2 );
}
imshow("Output",img);
imshow("Contours",drawing);
waitKey(0);
return 0;
}
Related
I am new to OpenCV, so apologies if I am not able to express my issue properly.
So, I have an image that I converted to B&W. Now I want to convert all big block (block could be of any shapes) of white pixels to black and leave the small white pixels as it is.
To further explain, please look at the picture below:
This pic
This is from another stackoverflow post but basically what I want to do is get rid of that white box and just have text in my picture. In this picture, I can just put a black box on the top since I know where that white box is but how can I do it when I don't know where that white box is?
Thanks in advance
Edit: An example of a picture that I want is here
You can use minArearect function. This function draws fitted rectangles for each contour. You can filter by setting these rectangle edge lengths.
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
int main()
{
Mat src; Mat src_gray;
int thresh = 100;
RNG rng(12345);
/// Load source image and convert it to gray
src = imread( "/ur/src/image_directory/image.png", 1 );
Mat original = src.clone();
/// Convert image to gray and blur it
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Threshold
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
/// Find contours
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Find the rotated rectangles for each contour
vector<RotatedRect> minRect( contours.size() );
for( int i = 0; i < contours.size(); i++ )
minRect[i] = minAreaRect( Mat(contours[i]) );
int x1,x2,y1,y2;
/// Draw contours + rotated rects
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
Mat result_zero = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
// contour
drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
// rotated rectangle
Point2f rect_points[4]; minRect[i].points( rect_points );
double length_1 = cv::norm(cv::Mat(rect_points[0]),cv::Mat(rect_points[1]));
double length_2 = cv::norm(cv::Mat(rect_points[1]),cv::Mat(rect_points[2]));
//This if scope for your desired rectangle size.You can set your size according to your rectangle(if it changes)
if(length_1>30 && length_1<100 && length_2>30 && length_2<100)
{
int min_x1 = INT_MAX, max_x2 = 0, min_y1 = INT_MAX, max_y2 = 0;
for( int j = 0; j < 4; j++ )
{
if(rect_points[j].x>max_x2 && rect_points[j].y>max_y2)
{
max_x2 = rect_points[j].x;
max_y2 = rect_points[j].y;
}
if(rect_points[j].x<min_x1 && rect_points[j].y<min_y1)
{
min_x1 = rect_points[j].x;
min_y1 = rect_points[j].y;
}
line( result_zero, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
}
x1 = min_x1;
x2 = max_x2;
y1 = min_y1;
y2 = max_y2;
}
}
circle(result_zero,Point(x1,y1),3,Scalar(0,255,255),2);
circle(result_zero,Point(x2,y2),3,Scalar(0,255,255),2);
// Here in source image we make the rectangle black according to found points
for(int i=y1-2;i<y2+2;i++)
{
for(int j=x1-2;j<x2+2;j++)
{
src.at<cv::Vec3b>(i,j)[0]=0;
src.at<cv::Vec3b>(i,j)[1]=0;
src.at<cv::Vec3b>(i,j)[2]=0;
}
}
/// Show in windows
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow("First",original);
imshow( source_window, result_zero );
imshow("Last",src);
imshow( "Contours", drawing );
waitKey(0);
return(0);
}
Source image:
Points:
Result:
Find contours.
For each contour: cv::Rect br = cv::boundingRect(contour)
bwImage(br) = cv::Scalar(0, 0, 0)
I am trying to use OpenCV to isolate the translucent darkened rectangular region which has lots of text overlayed. These rectanglular regions can vay in size and location in the window. Is there a way to detect these darkened regions?
Maybe it would be easier to apply some diff operation and compare to the frame before the dark region overlay is shown?
This should give you all bounding boxes based on two images.
#include <cv.h>
#include <highgui.h>
using namespace cv;
Mat im = imread("original.jpg");
Mat im2 = imread("darkened.jpg");
Mat diff_im = im - im2;
Mat diff_im_binary;
threshold(diff_im, diff_im_binary, 30, 255, THRESH_BINARY);
findContours(diff_im_binary, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Approximate contours to polygons + get bounding rects and circles
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
vector<Point2f>center( contours.size() );
vector<float>radius( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) );
}
Extracting different size rectangles from image using opencv does not work correctly
It doesn't give us patches of all character, just give one patch, but I want patches of all characters
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
void thresh_callback(int, void* );
/** #function main */
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
src = imread( "1a.bmp" );
/// Convert image to gray and blur it
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src );
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
}
/** #function thresh_callback */
void thresh_callback(int, void* )
{
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Threshold
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
/// Find contours
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Approximate contours to polygons + get bounding rects and circles
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
vector<Point2f>center( contours.size() );
vector<float>radius( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) );
minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] );
}
/// Draw polygonal contour + bonding rects + circles
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
//circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );
}
/// Show in a window
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
for(int i = 0; i < boundRect.size(); i++)
{
Mat patch = src(boundRect[i]);
//Do whatever you want with the patch (imshow, imwrite,...)
imshow("Patch",patch);
}
}
I think you don't have to extract the rectangles, because you already have them in your vector<Rect> boundRect.
If you want to get patches of the image that contain the rectangles/characters, you just need to cut them out:
stringstream ss;
for(int i = 0; i < boundRect.size(); i++)
{
ss>>"Patch ">>i;
Mat patch = src(boundRect[i]);
//Do whatever you want with the patch (imshow, imwrite,...)
imshow(ss.str(), patch);
ss.str("");
}
#user, you can also try this in opencv documentation
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contours = 0;
cvFindContours( img, storage, &contours, sizeof(CvContour),
CV_RETR_LIST , CV_CHAIN_APPROX_NONE, cvPoint(0,0) );
for( CvSeq* c=contours; c!=NULL; c=c->h_next)
{
CvRect Rects = cvBoundingRect( c );
}
#dennis i also need to extract line. guide me also
I am trying a number recognition. However after contour finding. I get bounding boxes inside the main bounding box for numbers 0,6,8 ... as shown in figure. Please help me with this initial step of image processing.
I have tried using group rectangles but they are not working. Please check the code below. Thank you.
Image: http://tinypic.com/r/1twx05/5
int main()
{
Mat inimage, gray;
inimage = imread("sample.jpg");
cvtColor(inimage, gray, COLOR_BGR2GRAY);
GaussianBlur(gray, gray, Size(5,5), 0);
adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 11, 0);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( gray, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) );
}
//groupRectangles(boundRect, 1, 0.2);
Scalar color = Scalar(0,0,255);
for( int i = 0; i< contours.size(); i++ )
{
//drawContours( inimage, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
rectangle( inimage, boundRect[i].tl(), boundRect[i].br(), color, 1, 8, 0 );
}
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", inimage );
waitKey(0);
return 0;
}
try to use the flag: CV_RETR_EXTERNAL instead of CV_RETR_TREE
as stated in the docs it tells to take only outer contours.
Or follow the tree hierarchy to drop nested contours (read the docs for how-to)
I am newbie in programming, so please help me. I want to retrieve only the outer contour of an object but the problem is I got another contour like a border. How can I get the only outer contour of object without any other contour?
An example image:
Here is the code I made:
// cvAutoHeight.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "opencv\cvaux.h"
#include "opencv\cxmisc.h"
#include "opencv\highgui.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdlib.h>
using namespace std;
using namespace cv;
int main(int, char**)
{
Mat threshold_output;
int thresh = 100;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
RNG rng(12345);
CvCapture* capture = cvCaptureFromCAM(0);
cv::Mat frame; cv::Mat src_gray;
while(1) {
frame = cvQueryFrame( capture );
cvtColor( frame,src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
//Canny( src_gray, threshold_output, 128, 255, 3 );
threshold( src_gray, threshold_output, 100, 200, THRESH_BINARY );
findContours( threshold_output, contours, hierarchy,CV_RETR_TREE,
CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Find the rotated rectangles and ellipses for each contour
vector<RotatedRect> minRect( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
minRect[i] = minAreaRect( Mat(contours[i]) );
}
/// Draw contours + rotated rects + ellipses
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0,0), rng.uniform(0,0), rng.uniform(250,250) );
// contour
drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0,
Point() );
// rotated rectangle
Point2f rect_points[4]; minRect[i].points( rect_points );
for( int j = 0; j < 4; j++ )
line( frame, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
}
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", frame );
cvWaitKey(33);
}
return 0;
}
`
by default, out of borders have 0 pixel value = black. after threshold, you get your black blob with white background. this why you have 2 contours. choose one of the solutions:
use binary threshold inverted.
apply canny after threshold.