OpenCV - 如何计算 Mat 的对数?
OpenCV - How to claculate logarithm of a Mat?
我正在尝试根据以下公式计算两个向量 X
和 Y
:
其中:
我决定使用两个 Mat 作为向量:
Mat X, Y, B, G, R, input_f;
// read RGB image
Mat input = imread("an RGB image");
// convert to float to deal with larger numbers
input.convertTo(input_f, CV_64FC3);
// split the image into 3 channels
vector<Mat> channels(3);
split(input_f, channels);
B = channels[0];
G = channels[1];
R = channels[2];
// calculate X , Y vectors
Mat div_x, div_y;
divide(R, G, div_x); // R(p_i) / G(p_i)
divide(B, G, div_y); // B(p_i) / G(p_i)
div_x.setTo(1, Mat(div_x == 0)); // set zeros to ones to avoid large negative numbers
div_y.setTo(1, Mat(div_y == 0));
log(div_x, X); // X = log(R(p_i) / G(p_i))
log(div_y, Y); // Y = log(B(p_i) / G(p_i))
因此,我在 documentaion:
中将零值更改为一
void log(InputArray src, OutputArray dst);
where C is a large negative number (about -700 in the current implementation).
我不想要大的负数,因为稍后我要将X
和Y
的所有像素值相加,总和变为-nan
。
我确定我取对数的方式有问题,因为结果是错误的。我应该如何以正确的方式做到这一点?
例如,对于这张图片:
X
和 Y
值应该是这样的(蓝点):
但就我而言,它们是这样的:
这些是垫子:
根据下面的答案,我将此添加到代码中以避免零除法:
R += 1;
B += 1;
G += 1;
但是现在我的情节看起来还是不一样:
根据下面的回答,修正了(OpenCV对数函数取绝对值的log):
很难说出您到底做错了哪一部分(矩阵除法、将零更改为一,或调用矩阵上的日志)。不管怎样,我只是根据你问题中的方程式实现了你的算法,我得到的结果或多或少是你所期望的(使用你的图像):
代码很简单,只是一步步计算方程:
cv::Mat bgr[3];
cv::Mat pic = cv::imread(PATH_TO_FILE);
cv::split(pic, bgr);
cv::Mat B = bgr[0];
cv::Mat G = bgr[1];
cv::Mat R = bgr[2];
std::vector<float> X;
std::vector<float> Y;
std::transform(R.data, R.data + R.total(), G.data, std::back_inserter(X),
[](uint8_t r, uint8_t g)
{
return std::log((float)r/(float)g);
});
std::transform(B.data, B.data + B.total(), G.data, std::back_inserter(Y),
[](uint8_t b, uint8_t g)
{
return std::log((float)b/(float)g);
});
使用 gnuplot 创建的图形。 X
X 轴向量,Y
Y 轴向量。 X.size() == Y.size() == 11532
.
您可能应该调查 G[i] == 0
情况下应该发生什么,因为您可能会得到 "Floating point exception"。也是分子和分母都为零的特殊情况。
如果你想避免大的负日志,只改变分子的值(比方说从 0 到 1)。不要改变除法结果,因为在大分母的情况下已经有很大的不同了。
我正在尝试根据以下公式计算两个向量 X
和 Y
:
其中:
我决定使用两个 Mat 作为向量:
Mat X, Y, B, G, R, input_f;
// read RGB image
Mat input = imread("an RGB image");
// convert to float to deal with larger numbers
input.convertTo(input_f, CV_64FC3);
// split the image into 3 channels
vector<Mat> channels(3);
split(input_f, channels);
B = channels[0];
G = channels[1];
R = channels[2];
// calculate X , Y vectors
Mat div_x, div_y;
divide(R, G, div_x); // R(p_i) / G(p_i)
divide(B, G, div_y); // B(p_i) / G(p_i)
div_x.setTo(1, Mat(div_x == 0)); // set zeros to ones to avoid large negative numbers
div_y.setTo(1, Mat(div_y == 0));
log(div_x, X); // X = log(R(p_i) / G(p_i))
log(div_y, Y); // Y = log(B(p_i) / G(p_i))
因此,我在 documentaion:
中将零值更改为一void log(InputArray src, OutputArray dst);
where C is a large negative number (about -700 in the current implementation).
我不想要大的负数,因为稍后我要将X
和Y
的所有像素值相加,总和变为-nan
。
我确定我取对数的方式有问题,因为结果是错误的。我应该如何以正确的方式做到这一点?
例如,对于这张图片:
X
和 Y
值应该是这样的(蓝点):
但就我而言,它们是这样的:
这些是垫子:
根据下面的答案,我将此添加到代码中以避免零除法:
R += 1;
B += 1;
G += 1;
但是现在我的情节看起来还是不一样:
根据下面的回答,修正了(OpenCV对数函数取绝对值的log):
很难说出您到底做错了哪一部分(矩阵除法、将零更改为一,或调用矩阵上的日志)。不管怎样,我只是根据你问题中的方程式实现了你的算法,我得到的结果或多或少是你所期望的(使用你的图像):
代码很简单,只是一步步计算方程:
cv::Mat bgr[3];
cv::Mat pic = cv::imread(PATH_TO_FILE);
cv::split(pic, bgr);
cv::Mat B = bgr[0];
cv::Mat G = bgr[1];
cv::Mat R = bgr[2];
std::vector<float> X;
std::vector<float> Y;
std::transform(R.data, R.data + R.total(), G.data, std::back_inserter(X),
[](uint8_t r, uint8_t g)
{
return std::log((float)r/(float)g);
});
std::transform(B.data, B.data + B.total(), G.data, std::back_inserter(Y),
[](uint8_t b, uint8_t g)
{
return std::log((float)b/(float)g);
});
使用 gnuplot 创建的图形。 X
X 轴向量,Y
Y 轴向量。 X.size() == Y.size() == 11532
.
您可能应该调查 G[i] == 0
情况下应该发生什么,因为您可能会得到 "Floating point exception"。也是分子和分母都为零的特殊情况。
如果你想避免大的负日志,只改变分子的值(比方说从 0 到 1)。不要改变除法结果,因为在大分母的情况下已经有很大的不同了。