在 x 方向和 y 方向计算一次 1st Sobel 导数并将这两者结合起来(对于每个通道)
Calculate 1st Sobel derivative once in x and once in y direction and combine these two(for every channel)
我需要一些帮助来解决我现在遇到的这个问题。
我有 3 张图像,它们只是不同之处相同,它们代表蓝色、绿色和红色。我需要将它们组合起来并得到彩色图像。
我正在使用 opencv 和 c++,但现在我遇到了这个问题,我无法弄清楚。
需要: 进行边缘检测。
----更新----
我写了一些新代码
Sobel(img_r, x, CV_16S, 1, 0);
Sobel(img_r, y, CV_16S, 0, 1);
//Compute the L1 norm
sobel_L1_norm = abs(x)+abs(y);
//Find Sobel max value
minMaxLoc(sobel_L1_norm, &min, &max);
sobel_L1_norm.convertTo(sobel_image, CV_32F, 255.0/(max - min), -min * 255.0/(max - min));
threshold(sobel_image, edgeThreshold, min, 255, THRESH_BINARY);
edgeThreshold.copyTo(img_r_edge);
我得到这个结果bad example
但应该是这样的。 correct one
----完整代码-----
Mat img_r = imread(input_path + "/01.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_g = imread(input_path + "/02.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_b = imread(input_path + "/03.png", CV_LOAD_IMAGE_GRAYSCALE);
// Edge Images
Mat img_r_edge = Mat::zeros(img_r.size(), CV_8UC1);
Mat img_g_edge = Mat::zeros(img_g.size(), CV_8UC1);
Mat img_b_edge = Mat::zeros(img_b.size(), CV_8UC1);
std::cout << "Step 1 - calculating edge images... ";
// TODO: 1) Calculate the 1st Sobel derivative once in x and once in y direction and combine these two
// (for every channel).
Mat x;
Mat y;
Mat abs_x;
Mat abs_y;
Mat sobel_L1_norm;
Mat sobel_image;
Mat edgeThreshold;
double min, max; //Finding min and max Sobel valuye;
//---------------------------------------------------
Sobel(img_r, x, CV_16S, 1, 0);
Sobel(img_r, y, CV_16S, 0, 1);
//Compute the L1 norm
sobel_L1_norm = abs(x)+abs(y);
//Find Sobel max value
minMaxLoc(sobel_L1_norm, &min, &max);
sobel_L1_norm.convertTo(sobel_image, CV_32F, 255.0/(max - min), -min * 255.0/(max - min));
threshold(sobel_image, edgeThreshold, min, 255, THRESH_BINARY);
edgeThreshold.copyTo(img_r_edge);
//----------------------------------------------------
// 2) Normalize every gradient image and convert the results to CV_8UC1.
// 3) Threshold the retrieved (normalized) gradient images using the parameter "edgeThreshold".
// 4) Save the results in the cv::Mats below.
imwrite(out_r_edge_filename, sobel);
imwrite(out_g_edge_filename, img_g_edge);
imwrite(out_b_edge_filename, img_b_edge);
您正在将 sobel_image
设为阈值 min
。
但是 min
将(几乎)总是 0
,因为它是 sobel_L1_norm
图像的最小值。请注意,没有渐变的像素在 sobel_L1_norm
.
中的值为 0
解决这个问题的方法是为阈值选择一个有意义的值。由于您将值标准化为 [0, 255]
范围内的值,因此您可以选择该范围内的值(大于 0)。
如果您使用 [0,1]
中的值进行标准化,请在此区间内选择一个值。
您可以使用 normalize(..., NORM_MINMAX)
而不是查找最大值和重新缩放。
还要注意 edgeThreshold
在调用 threshold
之后将是 CV_32F
类型的矩阵,因此它也将是 img_r_edge
。要使用 imwrite
正确保存图像,请使用 [0,1]
范围内的 CV_32F
个图像,或 [0,255] 范围内的 CV_8U
个图像。因此,您需要在 [0,1]
范围内重新缩放 img_r_edge
,或者将其转换为 CV_8U
.
您在这里混合了很多 OpenCV 类型。使用 Mat_<Tp>
通常更容易准确地知道类型。
您始终可以使用 CV_32F
张图像,范围在 [0,1] 内。
将产生正确输出的代码,建议修改:
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
Mat3b img = imread(path_to_color_image");
vector<Mat1b> planes;
split(img, planes);
Mat1b img_r = planes[2].clone();
Mat1b img_g = planes[1].clone();
Mat1b img_b = planes[0].clone();
// Edge Images
Mat1b img_r_edge;
Mat1b img_g_edge;
Mat1b img_b_edge;
// TODO: 1) Calculate the 1st Sobel derivative once in x and once in y direction and combine these two
// (for every channel).
Mat1f dx, dy;
Mat1f sobel_L1_norm;
Mat1f sobel_image;
Mat1f edgeThreshold;
double min, max; //Finding min and max Sobel valuye;
//---------------------------------------------------
Sobel(img_r, dx, CV_32F, 1, 0);
Sobel(img_r, dy, CV_32F, 0, 1);
//Compute the L1 norm
sobel_L1_norm = abs(dx) + abs(dy); // Type
// Normalize
normalize(sobel_L1_norm, sobel_image, 0, 1, NORM_MINMAX);
// Use a value different from 'min', which will (almost always) be 0.
double thresh = 0.5;
threshold(sobel_image, edgeThreshold, thresh, 255, THRESH_BINARY);
edgeThreshold.convertTo(img_r_edge, CV_8U);
imwrite("img_r_edge.png", img_r_edge);
return 0;
}
我需要一些帮助来解决我现在遇到的这个问题。 我有 3 张图像,它们只是不同之处相同,它们代表蓝色、绿色和红色。我需要将它们组合起来并得到彩色图像。 我正在使用 opencv 和 c++,但现在我遇到了这个问题,我无法弄清楚。
需要: 进行边缘检测。
----更新---- 我写了一些新代码
Sobel(img_r, x, CV_16S, 1, 0);
Sobel(img_r, y, CV_16S, 0, 1);
//Compute the L1 norm
sobel_L1_norm = abs(x)+abs(y);
//Find Sobel max value
minMaxLoc(sobel_L1_norm, &min, &max);
sobel_L1_norm.convertTo(sobel_image, CV_32F, 255.0/(max - min), -min * 255.0/(max - min));
threshold(sobel_image, edgeThreshold, min, 255, THRESH_BINARY);
edgeThreshold.copyTo(img_r_edge);
我得到这个结果bad example
但应该是这样的。 correct one
----完整代码-----
Mat img_r = imread(input_path + "/01.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_g = imread(input_path + "/02.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_b = imread(input_path + "/03.png", CV_LOAD_IMAGE_GRAYSCALE);
// Edge Images
Mat img_r_edge = Mat::zeros(img_r.size(), CV_8UC1);
Mat img_g_edge = Mat::zeros(img_g.size(), CV_8UC1);
Mat img_b_edge = Mat::zeros(img_b.size(), CV_8UC1);
std::cout << "Step 1 - calculating edge images... ";
// TODO: 1) Calculate the 1st Sobel derivative once in x and once in y direction and combine these two
// (for every channel).
Mat x;
Mat y;
Mat abs_x;
Mat abs_y;
Mat sobel_L1_norm;
Mat sobel_image;
Mat edgeThreshold;
double min, max; //Finding min and max Sobel valuye;
//---------------------------------------------------
Sobel(img_r, x, CV_16S, 1, 0);
Sobel(img_r, y, CV_16S, 0, 1);
//Compute the L1 norm
sobel_L1_norm = abs(x)+abs(y);
//Find Sobel max value
minMaxLoc(sobel_L1_norm, &min, &max);
sobel_L1_norm.convertTo(sobel_image, CV_32F, 255.0/(max - min), -min * 255.0/(max - min));
threshold(sobel_image, edgeThreshold, min, 255, THRESH_BINARY);
edgeThreshold.copyTo(img_r_edge);
//----------------------------------------------------
// 2) Normalize every gradient image and convert the results to CV_8UC1.
// 3) Threshold the retrieved (normalized) gradient images using the parameter "edgeThreshold".
// 4) Save the results in the cv::Mats below.
imwrite(out_r_edge_filename, sobel);
imwrite(out_g_edge_filename, img_g_edge);
imwrite(out_b_edge_filename, img_b_edge);
您正在将 sobel_image
设为阈值 min
。
但是 min
将(几乎)总是 0
,因为它是 sobel_L1_norm
图像的最小值。请注意,没有渐变的像素在 sobel_L1_norm
.
0
解决这个问题的方法是为阈值选择一个有意义的值。由于您将值标准化为 [0, 255]
范围内的值,因此您可以选择该范围内的值(大于 0)。
如果您使用 [0,1]
中的值进行标准化,请在此区间内选择一个值。
您可以使用 normalize(..., NORM_MINMAX)
而不是查找最大值和重新缩放。
还要注意 edgeThreshold
在调用 threshold
之后将是 CV_32F
类型的矩阵,因此它也将是 img_r_edge
。要使用 imwrite
正确保存图像,请使用 [0,1]
范围内的 CV_32F
个图像,或 [0,255] 范围内的 CV_8U
个图像。因此,您需要在 [0,1]
范围内重新缩放 img_r_edge
,或者将其转换为 CV_8U
.
您在这里混合了很多 OpenCV 类型。使用 Mat_<Tp>
通常更容易准确地知道类型。
您始终可以使用 CV_32F
张图像,范围在 [0,1] 内。
将产生正确输出的代码,建议修改:
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
Mat3b img = imread(path_to_color_image");
vector<Mat1b> planes;
split(img, planes);
Mat1b img_r = planes[2].clone();
Mat1b img_g = planes[1].clone();
Mat1b img_b = planes[0].clone();
// Edge Images
Mat1b img_r_edge;
Mat1b img_g_edge;
Mat1b img_b_edge;
// TODO: 1) Calculate the 1st Sobel derivative once in x and once in y direction and combine these two
// (for every channel).
Mat1f dx, dy;
Mat1f sobel_L1_norm;
Mat1f sobel_image;
Mat1f edgeThreshold;
double min, max; //Finding min and max Sobel valuye;
//---------------------------------------------------
Sobel(img_r, dx, CV_32F, 1, 0);
Sobel(img_r, dy, CV_32F, 0, 1);
//Compute the L1 norm
sobel_L1_norm = abs(dx) + abs(dy); // Type
// Normalize
normalize(sobel_L1_norm, sobel_image, 0, 1, NORM_MINMAX);
// Use a value different from 'min', which will (almost always) be 0.
double thresh = 0.5;
threshold(sobel_image, edgeThreshold, thresh, 255, THRESH_BINARY);
edgeThreshold.convertTo(img_r_edge, CV_8U);
imwrite("img_r_edge.png", img_r_edge);
return 0;
}