Open cv C++ detect shapes on an image does not draw over the original image

I am trying to detect rectangular shapes on a sample image with the following code in cpp. I have a list that holds objects of the type cv::Rect then I use a method called cv::findContours() to try and detect all the contours from a gray scale image. I then loop through each contour detected and check if it qualifies to be a rectangle and push it to my list. I then loop through the list of rectangles and draw over them and save the final image to disk. The code is able to draw over all the shapes detected over the image with edges but does not draw a thing over the original color image. How do I draw over the shapes detected over the original image and save to hard drive.
Please the code below for more information on my attempt at this.

    cv::Mat image ;
	cv::Mat  edges;
	image = cv::imread(name, cv::IMREAD_GRAYSCALE);
	//call the function to detect the edges
	cv::Canny(image, edges, 200, 200);
	//save the image
	cv::imwrite("edges.png", edges);
	//declare a new shape for detecting the shapes from the edged image
	std::vector<std::vector<cv::Point>> contours;
	cv::Mat input = cv::imread("edges.png", cv::IMREAD_GRAYSCALE);
	//detect contors from the image
	cv::findContours(input, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
	//list to hold the rectangular contours
	std::list<cv::Rect> rects;
	//iterate through the contours
	for (int i = 0;i < contours.size();i++) {
		std::vector<cv::Point> approx = std::vector<cv::Point>();
		//check if the contour is rectangular
		cv::approxPolyDP(contours[i], approx, cv::arcLength(contours[i], true) * 0.02, true);
		if (approx.size() == 4) {
			//this contour is rectangular, get the bounding rect and add to a list
			cv::Rect rect = cv::boundingRect(contours[i]);
			//add the rect to a list
			rects.push_back(rect);
		}
	}
	if (rects.size() > 0) {
		for (std::list<cv::Rect>::iterator it = rects.begin();it != rects.end();++it) {
			//get the rect
			cv::Rect rect = *it;
			cv::rectangle(input, rect, cv::Scalar(250, 128, 114), 5);
		}
		//save the final image
		cv::imwrite("shapes.png", input);
	}

terrible noob code, hehe :wink:

some notes:

  • if it did not draw anything, then first assume, it did not find any Rects, before ! (go check !)
  • visualize ALL intermediate steps (imshow), print out sizes numbers, etc.
  • you’ll get arbitrarily oriented rectangles, not axis-aligned ones, so use minAreaRect(), not boundingRect()
  • even, IF it draws anything, you won’t see it, trying to draw colored Rects into a single channel image (input !) will only lead to white lines on white edges

Hi, it draws the rectangles with a white marker pen on the black and white version of the image with edges. But when I try to replace the input parameter with image in the cv::rectangle method then it saves an image with no white lines drawn over it. I thought drawing over an image object with open cv is like drawing over an image inside a glass frame where the original image is unaffected.

Both ‘image’ and ‘input’ are grayscale

not possible to draw colors into that

Then o need to load the original image on color mode then attemp to draw the rectangles over them?

1 Like

well no, boundingRect does return a Rect. minAreaRect returns a RotatedRect (with angle)

image = cv::imread(name, cv::IMREAD_GRAYSCALE);

name is undefined at this point. if I assume it is defined somehow, then… image will probably contain something, or else it’s an empty Mat.

make sure the imread() succeeded. you can check with image.empty(), or print the shape/size of the result, or imshow() the data.

whyyyy? why do you write-then-read the same file?

look up cv::cvtColor(). it will probably help you.

Hi, i am trying to detect shapes from the image with edges as its easier to do it from a canny edged image, thats why am saving the image to a file then i use it to detect the shapes.

that wasn’t my question.

I’m asking why you don’t simply use the edges variable? that already contains the information. saving-then-reading to file does absolutely nothing, except create a file and maybe change the data in silly ways that you can also get without writing-then-reading a file.

I’m actually not asking why because I don’t anticipate a good reason. I am suggesting that you not do that and instead use the edges variable in place of (instead of) the input variable.