Reputation: 63
I have recently started working on opencv. I have an image having several dots in a line. I want to make a rectangular border around these dots. I have applied some basic C algorithm but it didn't work for me. This is my code.
int main()
{
cv::Mat image = imread("C:/Users/Ravi Sharma/Desktop/img.bmp");
for(int i =0; i < image.rows; i++){
for(int k = 0; k <image.cols; k ++){
if((image.at<cv::Vec3b>(k,i)[0] == 0)&&(image.at<cv::Vec3b>(k,i)[1] == 135)&&(image.at<cv::Vec3b>(k,i)[2] == 255))
{
(image.at<cv::Vec3b>(k,i)[0] = 0)&&(image.at<cv::Vec3b>(k,i)[1] = 0)&&(image.at<cv::Vec3b>(k,i)[2] = 255);
}
}
}
imwrite("C:/Users/Ravi Sharma/Desktop/img1.bmp",image);
cv::namedWindow("Window1");
cv::imshow("Window1",image);
cv::waitKey(50000);
return 1;
}
This code is not updating the pixel value. Please help me correcting the code to get the desired result. How I can use cvminmaxloc function to do the same. Thanx in advance.
Upvotes: 0
Views: 2294
Reputation: 2524
I will assume that your image can be treated as a binary mask and that we are only interested in pixels with non-zero values.
To find the bounding box around the points in the left image above, iterate over all pixels in the image. For every non-zero pixel, check if its xy
-location lies outside the current bounding box. If it does, then update your bounding box. The resulting bounding box will enclose all points, as in the right image above.
Below is a minimally working example, which generates an image containing randomly sampling points for which a bounding box is determined.
// This example uses OpenCV 3.0.0-beta. To use with OpenCV 2.4.* a
// few changes have to be made.
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
cv::Mat randomPoints( cv::Size size = cv::Size( 320, 240 ), int pointCount = 25 )
{
cv::RNG rng( cv::getCPUTickCount() );
cv::Mat image = cv::Mat3b::zeros( size );
int radius = 3;
cv::Scalar color( 0, 153, 255 );
int thickness = -1;
int margin = std::min( size.height, size.width ) / 4;
for ( int i = 0; i < pointCount; ++i )
{
cv::Point p;
p.x = rng.uniform( margin, size.width - margin - 1 );
p.y = rng.uniform( margin, size.height - margin - 1 );
cv::circle( image, p, radius, color, thickness );
}
return image;
}
int main( int argc, char ** argv )
{
#if 0
cv::Mat image = imread( "C:/Users/Ravi Sharma/Desktop/img.bmp" );
#else
cv::Mat image = randomPoints();
#endif
cv::Mat imageGray;
cv::cvtColor( image, imageGray, cv::COLOR_BGR2GRAY );
cv::Size size = imageGray.size();
// The bounding box is defined by its top-left (TL) and bottom-right (BR)
// coordinates.
cv::Point tl( size.width, size.height );
cv::Point br( 0, 0 );
bool hasPoints = false;
for ( int y = 0; y < size.height; ++y )
{
for ( int x = 0; x < size.width; ++x )
{
if ( imageGray.at<unsigned char>( y, x ) > 0 )
{
hasPoints = true;
// Update the top-left corner.
if ( x < tl.x ) tl.x = x;
if ( y < tl.y ) tl.y = y;
// Update the bottom-right corner.
if ( x > br.x ) br.x = x;
if ( y > br.y ) br.y = y;
}
}
}
// If the image contains any non-zero pixels, then draw the bounding box.
if ( hasPoints )
cv::rectangle( image, tl, br, cv::Scalar( 255, 255, 255, 255 ) );
cv::namedWindow( "bounding-box" );
cv::imshow( "bounding-box", image );
cv::waitKey( 0 );
cv::imwrite( "bounding-box.png", image );
}
EDIT 1:
I also like the idea suggested by @Micka above, i.e. using cv::boundingRect(). So, inside the loop in the above code example you would push all xy
-locations of non-zeros pixels into a std::vector< cv::Point >
and then call cv::boundingRect
. In that context it is also interesting to look at the convex hull of a 2D point cloud.
Upvotes: 1
Reputation: 576
Here's a quick example specifically using cvminmaxloc, my Python isn't great but I don't have OpenCV setup for C++ here, hopefully it should be understandable.
Starting image:
Result image:
import cv2
import copy
import numpy
#Read in image
img = cv2.imread("Line.png")
#Top Left Point
y1,x1 = img.shape[:2]
#Bottom right point
y2,x2 = 0, 0
#Values returned from minmaxloc
min_val, max_val, min_loc, max_loc = 0,0,(0,0),(0,0)
#create grayscale copy of our img to work with
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Get values
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(gray_img)
#White = 255 #Black = 0
while(min_val != 255):
#Check points and update if needed
if(min_loc[0] < x1):
x1 = min_loc[0]
if(min_loc[1] < y1):
y1 = min_loc[1]
if(min_loc[0] > x2):
x2 = min_loc[0]
if(min_loc[1] > y2):
y2 = min_loc[1]
#Update image - remove current result
gray_img[min_loc[1], min_loc[0]] = 255
#Get next values
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(gray_img)
#Done checking - draw rectangle over reference + display
cv2.rectangle(img, (x1,y1), (x2, y2), (0,255,0), 1)
#Display
cv2.namedWindow('image')
cv2.imshow('image', img)
cv2.waitKey(0)
#Clear up windows
cv2.destroyAllWindows()
#Write result
cv2.imwrite('result.png',img)
Upvotes: 0