Related
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;
}
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 have got the corner points and I'm trying to fit the lines using cv::fitline
but I get lines that are from the origin 0,0 that are shown in the picture.
I also have the projection matrix and the view matrix and the camera intersincs parameters if that would help
I'm trying to compute the volume of the box that is in the figure
int main( int argc, char** argv )
{
Mat src, src_copy, edges, dst;
src = imread( "freezeFrame__1508152029892.png", 0 );
src_copy = src.clone();
GaussianBlur( src, edges, Size( 5, 5 ), 1.5, 1.5 );
erode( edges, edges, Mat() );// these lines may need to be optimized
dilate( edges, edges, Mat() );
dilate( edges, edges, Mat() );
erode( edges, edges, Mat() );
Canny( edges, dst, 1, 10, 3 ); // canny parameters may need to be optimized
imshow( "canny", dst );
std::vector< cv::Point2f > corners;
// maxCorners – The maximum number of corners to return. If there are more corners
// than that will be found, the strongest of them will be returned
int maxCorners = 10;
// qualityLevel – Characterizes the minimal accepted quality of image corners;
// the value of the parameter is multiplied by the by the best corner quality
// measure (which is the min eigenvalue, see cornerMinEigenVal() ,
// or the Harris function response, see cornerHarris() ).
// The corners, which quality measure is less than the product, will be rejected.
// For example, if the best corner has the quality measure = 1500,
// and the qualityLevel=0.01 , then all the corners which quality measure is
// less than 15 will be rejected.
double qualityLevel = 0.01;
// minDistance – The minimum possible Euclidean distance between the returned corners
double minDistance = 20.;
// mask – The optional region of interest. If the image is not empty (then it
// needs to have the type CV_8UC1 and the same size as image ), it will specify
// the region in which the corners are detected
cv::Mat mask;
// blockSize – Size of the averaging block for computing derivative covariation
// matrix over each pixel neighborhood, see cornerEigenValsAndVecs()
int blockSize = 3;
// useHarrisDetector – Indicates, whether to use operator or cornerMinEigenVal()
bool useHarrisDetector = false;
// k – Free parameter of Harris detector
double k = 0.04;
cv::goodFeaturesToTrack( src, corners, maxCorners, qualityLevel, minDistance, mask, blockSize, useHarrisDetector, k );
std::vector<Vec4f> lines;
for ( int i = 0; i < corners.size(); i++ )
{
cv::Point2f pt = corners[i];
for ( int j = i + 1; j < corners.size(); j++ )
{
cv::Point2f endpt = corners[j];
std::vector<cv::Point2f> points;
points.push_back( pt );
points.push_back( endpt );
Vec4f line;
cv::fitLine( points, line, CV_DIST_L2, 0, 0.01, 0.01 );
lines.push_back( line );
}
}
for ( size_t i = 0; i < lines.size(); i++ )
{
cv::Vec4i v = lines[i];
line( src, Point( v[0], v[1] ), Point( v[2], v[3] ), Scalar( 0, 0, 255 ), 3, 4 );
}
for ( size_t i = 0; i < corners.size(); i++ )
{
cv::circle( src, corners[i], 10, cv::Scalar( 255. ), -1 );
}
imshow( "line src", src );
imshow("line dest", edges );
cv::waitKey( 0 );
return 0;
}
Read the doc:
line – Output line parameters. In case of 2D fitting, it should be a vector of 4 elements (like Vec4f) - (vx, vy, x0, y0), where (vx, vy) is a normalized vector collinear to the line and (x0, y0) is a point on the line. In case of 3D fitting, it should be a vector of 6 elements (like Vec6f) - (vx, vy, vz, x0, y0, z0), where (vx, vy, vz) is a normalized vector collinear to the line and (x0, y0, z0) is a point on the line.`
So you have to draw your line by:
Point2f linePoint = Point2f( v[2], v[3] );
Point2f lineDirection = Point2f( v[0], v[1]);
float factor = 50; // if lineDirection is already length 1, you could choose factor to be the desired line length
line( src, linePoint , linePoint+ factor*lineDirection + , Scalar( 0, 0, 255 ), 3, 4 );`
I need some help in detecting the dominant intensity area of an image. Suppose I have the following images and I like to automatically detect the dominant intensity area and find the mean/average intensity value of that dominant area.
Here, in Image-1, the dominant intensity area is the area with light gray color and in Image-2, the dominant area is with the dark gray color. How can I detect the dominant areas in those images and find the mean intensity value of the dominant area.
Image-1:
Image-2:
Any suggestion will be helpful!
Update: I used the following codes to get the histogram for Image-2. Figure-3 shows the histogram. Now, I need to find out which bin holds the most of the values i.e. the mode of the histogram. But, couldn't figure out how to calculate the bin with most of the values.
Figure-3:
int main(int, char**)
{
Mat gray=imread("Depth_frames_27/Image23.png",0);
namedWindow( "Gray", 1 ); imshow( "Gray", gray );
// Initialize parameters
int histSize = 256; // bin size
float range[] = { 0, 255 };
const float *ranges[] = { range };
// Calculate histogram
MatND hist;
calcHist( &gray, 1, 0, Mat(), hist, 1, &histSize, ranges, true, false );
double minVal=0, maxVal=0;
minMaxLoc(hist, &minVal, &maxVal, 0, 0);
// cout<<"Max:"<<maxVal<<endl;
// cout<<"Min:"<<minVal<<endl;
// Show the calculated histogram in command window
double total;
total = gray.rows * gray.cols;
for( int h = 0; h < histSize; h++ )
{
float binVal = hist.at<float>(h);
cout<<" "<<binVal;
}
// Plot the histogram
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC1, Scalar( 0,0,0) );
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
}
namedWindow( "Result", 1 ); imshow( "Result", histImage );
waitKey();
return 0;
}
Update-2: Worked out finally! I did the following to get the location and value of the maximum bin of the histogram.
double minVal=0, maxVal=0; int minIdx, maxIdx;
minMaxIdx(hist,&minVal,&maxVal, &minIdx, &maxIdx);
cout<<"Max:"<<maxVal<<endl;
cout<<"MaxIdx:"<<maxIdx<<endl;
The MaxIdx gives the location of the highest bin of the histogram and that's the dominant intensity value for the image!
What you are after is the mode of the histogram of intensities (the bin with the highest frequency). It directly tells you the average intensity.
For the given images, the histogram is made of two perfectly sharp peaks.
In some bad cases, the main peak can be spread over several secondary peaks. In such cases, you need to apply smoothing to the histogram before taking the mode.
It can be interesting to look at the relative heights of the first and second maxima, to check how dominant the color is.
I want to create a histogram for an green component of an image in c++ using OpenCV.
The following code is working fine for color image but once i split the image into its RGB component and using the green component to call calcHist function, I am getting the following error.
OpenCV Error: Assertion failed (j < nimages) in histPrepareImages, file /root/src/OpenCV-2.4.1/modules/imgproc/src/histogram.cpp, line 148
terminate called after throwing an instance of 'cv::Exception'
what(): /root/src/OpenCV-2.4.1/modules/imgproc/src/histogram.cpp:148: error: (-215) j < nimages in function histPrepareImages
Aborted (core dumped)
Here is my code for the same.
I took two images to create the histogram. Anyone pls help so solve this problem.
#include <cv.h>
#include <highgui.h>
using namespace cv;
int main( int argc, char** argv )
{
Mat src,src1, hsv, hsv1;
if( argc != 3 || !(src=imread(argv[1], 1)).data || !(src=imread(argv[2], 1)).data)
return -1;
std::vector<cv::Mat> three_channels;
cv::split(src,three_channels);
std::vector<cv::Mat> three_channels1;
cv::split(src1,three_channels1);
//cvtColor(src, hsv, CV_BGR2HSV);
//cvtColor(src1, hsv1, CV_BGR2HSV);
// Quantize the hue to 30 levels
// and the saturation to 32 levels
int hbins = 30, sbins = 32;
int histSize[] = {hbins, sbins};
// hue varies from 0 to 179, see cvtColor
float hranges[] = { 0, 180 };
// saturation varies from 0 (black-gray-white) to
// 255 (pure spectrum color)
float sranges[] = { 0, 256 };
const float* ranges[] = { hranges, sranges };
MatND hist, hist1, difference;
// we compute the histogram from the 0-th and 1-st channels
int channels[] = {0, 1};
calcHist( &three_channels[1], 1, channels, Mat(), // do not use mask
hist, 2, histSize, ranges,
true, // the histogram is uniform
false );
calcHist( &three_channels1[1], 1, channels, Mat(), // do not use mask
hist1, 2, histSize, ranges,
true, // the histogram is uniform
false );
double maxVal=0;
minMaxLoc(hist, 0, &maxVal, 0, 0);
minMaxLoc(hist1, 0, &maxVal, 0, 0);
int scale = 10;
Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
Mat hist1Img = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
Mat hist2Img = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
double hist_diff =0;
hist_diff = compareHist(hist, hist1, CV_COMP_CORREL);
absdiff(hist, hist1, difference);
printf("\nHist Diff: %f\n", hist_diff);
for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
{
float binVal = hist.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
rectangle( histImg, Point(h*scale, s*scale),
Point( (h+1)*scale - 1, (s+1)*scale - 1),
Scalar::all(intensity),
CV_FILLED );
}
for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
{
float binVal = hist1.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist1Img, Point(h*scale, s*scale),
Point( (h+1)*scale - 1, (s+1)*scale - 1),
Scalar::all(intensity),
CV_FILLED );
}
for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
{
float binVal = difference.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist2Img, Point(h*scale, s*scale),
Point( (h+1)*scale - 1, (s+1)*scale - 1),
Scalar::all(intensity),
CV_FILLED );
}
namedWindow( "Source", 1 );
imshow( "Source", src );
namedWindow( "H-S Histogram", 1 );
imshow( "H-S Histogram", histImg );
namedWindow( "H-S Histogram1", 1 );
imshow( "H-S Histogram1", hist1Img );
namedWindow( "H-S Histogram2", 1 );
imshow( "H-S Histogram2", hist2Img );
waitKey();
}
You're trying to calculate the histogram of two channels (0 and 1) from an image that has only one channel, as you splitted it.
I did not look at your code in detail, but I guess you could omit the splitting and pass src/src1 to calcHist instead of three_channels[1]/three_channels1[1], setting channels = {1}
EDIT
In your code, change channels = {0,1} to channels{0}, you should not get any errors.
You're passing a single-channel image to calcHist(), that's why you should only use channel 0 (the only one). By passing three_channels[1] as input image, you're making sure that you're actually analysing the second channel of your input image.
OR do the following:
int channels[] = {1};
calcHist( &src, 1, channels, Mat(), // do not use mask
hist, 2, histSize, ranges,
true, // the histogram is uniform
false );
You don't need to cv::split(src,three_channels) anymore.
That's two versions that compile, but you actually want to compute a green (1D) histogram and not a 2D histogram. So here's your edited code, that (hopefully) does, what you want:
int main( int argc, char** argv )
{
Mat src,src1;
if( argc != 3 || !(src=imread(argv[1], 1)).data || !(src=imread(argv[2], 1)).data)
return -1;
// Quantize the green to 30 levels
int greenbins = 30;
int histSize[] = {greenbins};
// green varies from 0 to 255 (pure spectrum color)
float greenranges[] = { 0, 256 };
const float* ranges[] = { greenranges };
MatND hist, hist1, difference;
// we compute the histogram from the 2nd channel (green, index is 1)
int channels[] = {1};
calcHist( &src, 1, channels, Mat(), // do not use mask
hist, 1, histSize, ranges,
true, // the histogram is uniform
false );
calcHist( &src1, 1, channels, Mat(), // do not use mask
hist1, 1, histSize, ranges,
true, // the histogram is uniform
false );
double maxVal1=0;
double maxVal2 =0;
minMaxLoc(hist, 0, &maxVal1, 0, 0);
minMaxLoc(hist1, 0, &maxVal2, 0, 0);
double maxVal = max(maxVal1, maxVal2);
int scale = 10;
int width = 50;
Mat histImg = Mat::zeros(greenbins*scale, width, CV_8UC3);
Mat hist1Img = Mat::zeros(greenbins*scale, width, CV_8UC3);
Mat hist2Img = Mat::zeros(greenbins*scale, width, CV_8UC3);
double hist_diff =0;
hist_diff = compareHist(hist, hist1, CV_COMP_CORREL);
absdiff(hist, hist1, difference);
printf("\nHist Diff: %f\n", hist_diff);
for( int h = 0; h<greenbins; ++h)
{
float binVal = hist.at<float>(h);
int intensity = cvRound(binVal*255/maxVal);
rectangle( histImg, Point(0, h*scale),
Point(width, (h+1)*scale),
Scalar::all(intensity),
CV_FILLED );
}
for( int h = 0; h<greenbins; ++h)
{
float binVal = hist1.at<float>(h);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist1Img, Point(0, h*scale),
Point(width, (h+1)*scale),
Scalar::all(intensity),
CV_FILLED );
}
for(int h = 0; h < greenbins; ++h)
{
float binVal = difference.at<float>(h);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist2Img, Point(0, h*scale),
Point(width, (h+1)*scale),
Scalar::all(intensity),
CV_FILLED );
}
imshow( "Source", src );
imshow( "Source1", src1 );
imshow( "src1 green Histogram", histImg );
imshow( "src2 green Histogram", hist1Img );
imshow( "diff green Histogram", hist2Img );
waitKey();
}