Undesired OpenCV color mixing

I wrote a short program that demonstrates Hough line detection using OpenCV.

At the last stage, the code takes the original, blurry image in shades of gray, superimposes the results of detecting coniferous edges, and then superimposes the detected hough conversion lines.

The hough lines are displayed as solid red (R = 255), 3px lines, however, when I overlap them, the image below is shown for some reason. An example is below.

Original Image: Original image

Blurred image with shades of gray with the edges of the cannon + Overlay hough-lines: enter image description here

Enlarged segment: enter image description here

As you can see, the image in shades of gray passes through a (apparently) solid red color. Why is this?

Full code below:

houghtest.cpp

#include <stdlib.h> #include <iostream> #include <stdio.h> #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include "toolbarconfig.h" using namespace cv; // Global variables const char* window_name = "Hough Line Detection"; ToolbarConfig gaussian = ToolbarConfig(0, 15, 1, 6), canny = ToolbarConfig(20, 150, 2, 40), hough = ToolbarConfig(50, 400, 10, 200); Mat input; // Function prototypes void update(int, void*); void chromakey(const Mat under, const Mat over, Mat *dst, const Scalar& color); void help(); /** * Creates an interactive example of running hough line detection on a * sample image */ int main( int argc, char** argv ) { const char* filename = argc >= 2 ? argv[1] : "pic1.png"; input = imread(filename, CV_LOAD_IMAGE_COLOR); if(input.empty()) { help(); std::cout << "Can not open " << filename << std::endl; return -1; } // Convert the image to grayscale cvtColor(input, input, CV_BGR2GRAY); // Create a window namedWindow(window_name, CV_WINDOW_AUTOSIZE); // Create trackbars for the user to enter thresholds createTrackbar("Gaussian Kernel Size", window_name, &(gaussian.t_current), gaussian.tmax(), update); createTrackbar("Canny Min Threshold", window_name, &(canny.t_current), canny.tmax(), update); createTrackbar("Hough Line Threshold", window_name, &(hough.t_current), hough.tmax(), update); // Show the image update(NULL, NULL); // Wait until user exit program by pressing a key waitKey(0); return 0; } /** * Trackbar callback - updates the display */ void update(int, void*) { const int CANNY_RATIO = 3, CANNY_KERNEL_SIZE = 3; Mat blurred_input, canny_edges, hough_lines; // Reduce noise with a gaussian kernel if(gaussian.current() != 0) { blur(input, blurred_input, Size(gaussian.current(), gaussian.current())); } else { blurred_input = input; } // Run Canny edge detector Canny(blurred_input, canny_edges, canny.current(), canny.current()*CANNY_RATIO, CANNY_KERNEL_SIZE); // ==== Begin Hough line detector phase // Create a vector to store the located lines in vector<Vec2f> line_vector; // Run the transform HoughLines(canny_edges, line_vector, 1, CV_PI/180, hough.current(), 0, 0); //std::cout << lines.size() << " lines detected" << std::endl; // Prepare the hough_lines image hough_lines = Mat::zeros(canny_edges.rows, canny_edges.cols, CV_8UC3); // Draw detected lines into an image for(size_t i = 0; i < line_vector.size(); i++) { float rho = line_vector[i][0], theta = line_vector[i][1]; Point pt1, pt2; double a = cos(theta), b = sin(theta); double x0 = a*rho, y0 = b*rho; pt1.x = cvRound(x0 + 1000*(-b)); pt1.y = cvRound(y0 + 1000*(a)); pt2.x = cvRound(x0 - 1000*(-b)); pt2.y = cvRound(y0 - 1000*(a)); line(hough_lines, pt1, pt2, Scalar(0, 0, 255), 3, 0); } // Overlay the hough lines onto the original blurred image Mat blurred_input_color, canny_edges_color, input_with_canny, combined_images; cvtColor(blurred_input, blurred_input_color, CV_GRAY2BGR); cvtColor(canny_edges, canny_edges_color, CV_GRAY2BGR); chromakey(blurred_input_color, canny_edges_color, &input_with_canny, Scalar(0, 0, 0)); chromakey(input_with_canny, hough_lines, &combined_images, Scalar(0, 0, 0)); // Display the result imshow(window_name, combined_images); } /** * Takes two images and overlays them, using color as a chroma-key * Any pixels in the 'over' image that match the given color value will * effectively be transparent - the 'under' image will show through * * @precondition: All passed images must first be in BGR format */ void chromakey(const Mat under, const Mat over, Mat *dst, const Scalar& color) { // Mats must be the same size if(under.rows != over.rows || under.cols != over.cols) { std::cout << "Error, image dimensions must match" << std::endl; return; } // Create the destination matrix *dst = Mat::zeros(under.rows, under.cols, CV_8UC3); for(int y=0; y<under.rows; y++) { for(int x=0; x<under.cols; x++) { dst->at<Vec3b>(y,x)[0] = over.at<Vec3b>(y,x)[0] == color[0] ? under.at<Vec3b>(y,x)[0] : over.at<Vec3b>(y,x)[0]; dst->at<Vec3b>(y,x)[1] = over.at<Vec3b>(y,x)[1] == color[1] ? under.at<Vec3b>(y,x)[1] : over.at<Vec3b>(y,x)[1]; dst->at<Vec3b>(y,x)[2] = over.at<Vec3b>(y,x)[2] == color[2] ? under.at<Vec3b>(y,x)[2] : over.at<Vec3b>(y,x)[2]; } } } /** * Prints usage information */ void help() { std::cout << "\nThis program demonstrates line finding with the Hough transform.\n" "Usage:\n" "./houghlines <image_name>, Default is pic1.png\n" << std::endl; } 

toolbarconfig.h

 #ifndef TOOLBARCONFIG_H #define TOOLBARCONFIG_H class ToolbarConfig { public: ToolbarConfig(int min, int max, int stepsize, int current); int w2t(int world_value); int t2w(int toolbar_value); int current(); int tmax(); int tmin(); int min; int max; int stepsize; int t_current; }; #endif 

toolbarconfig.cpp

 #include <algorithm> #include "toolbarconfig.h" ToolbarConfig::ToolbarConfig(int min, int max, int stepsize, int current) { this->min = min; this->max = max; this->stepsize = stepsize; this->t_current = this->w2t(current); } int ToolbarConfig::w2t(int world_value) { return int((std::min(std::max(world_value, min), max) - min) / stepsize); } int ToolbarConfig::t2w(int toolbar_value) { return toolbar_value * stepsize + min; } int ToolbarConfig::current() { return t2w(t_current); } int ToolbarConfig::tmax() { return w2t(max); } int ToolbarConfig::tmin() { return w2t(min); } 

We will also be pleased to provide a Makefile if necessary.

Thanks in advance.

+4
source share
1 answer

The error should be here:

 dst->at<Vec3b>(y,x)[0] = over.at<Vec3b>(y,x)[0] == color[0] ? under.at<Vec3b>(y,x)[0] : over.at<Vec3b>(y,x)[0]; dst->at<Vec3b>(y,x)[1] = over.at<Vec3b>(y,x)[1] == color[1] ? under.at<Vec3b>(y,x)[1] : over.at<Vec3b>(y,x)[1]; dst->at<Vec3b>(y,x)[2] = over.at<Vec3b>(y,x)[2] == color[2] ? under.at<Vec3b>(y,x)[2] : over.at<Vec3b>(y,x)[2]; 

On first call

 chromakey(blurred_input_color, canny_edges_color, &input_with_canny, Scalar(0, 0, 0)); 

the canny_edges_color white pixel canny_edges_color is (255, 255, 255), so in the above comparisons you will get over values ​​for each channel, so the pixel color will be (255, 255, 255) and the image will display correctly.

However, in the second case:

 chromakey(input_with_canny, hough_lines, &combined_images, Scalar(0, 0, 0)); 

your hugh_lines red pixels have a value of (0, 0, 255), so for the first two comparisons they will get a value of under , since

over.at<Vec3b>(y,x)[0] == color[0] and

over.at<Vec3b>(y,x)[1] == color[1] .

Only dst->at<Vec3b>(y,x)[2] will get the value 255. In order for the line to appear solid, in this case it should be dst->at<Vec3b>(y,x)[0] = 0 and dst->at<Vec3b>(y,x)[1] = 0 .


Also, according to this answer , you should probably initialize * dst as follows:

*dst = Mat(under.rows,under.cols,CV_8UC3,CV_RGB(0,0,0));

since it is a 3 channel Mat.

+7
source

Source: https://habr.com/ru/post/1434539/


All Articles