OpenCV - 如何计算垫子的对数?
Posted
技术标签:
【中文标题】OpenCV - 如何计算垫子的对数?【英文标题】:OpenCV - How to claculate logarithm of a Mat? 【发布时间】:2020-02-27 14:25:16 【问题描述】:我正在尝试根据这个公式计算两个向量 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);
其中 C 是一个很大的负数(在当前实现中约为 -700)。
我不想要大的负数,因为稍后我要将X
和Y
的所有像素值相加,总和变为-nan
。
我确定我取对数的方式有问题,因为结果是错误的。我应该如何以正确的方式做到这一点?
例如,对于这张图片:
X
和 Y
值应该是这样的(蓝点):
但就我而言,它们是这样的:
这些是垫子:
根据下面的答案,我将这个添加到代码中以避免零除:
R += 1;
B += 1;
G += 1;
但现在我的情节看起来仍然不同:
基于以下答案,已修复(OpenCV 对数函数采用绝对值的对数):
【问题讨论】:
出了点问题……因为结果是错误的您能否更具体地说明什么是错误的,即预期什么,得到了什么? @S.M.我为这个问题添加了一个情节。纵轴为log(B/G)
,横轴为log(R/G)
。
【参考方案1】:
很难判断您到底在哪一部分做错了(矩阵除法、将零更改为一或调用登录矩阵)。无论如何,我只是根据您的问题中的方程式实现了您的算法,我获得的结果或多或少是您所期望的(使用您的图像):
代码很简单,只是一步一步的方程求值:
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
的情况应该发生什么,因为您可能会收到“浮点异常”。分子和分母都为零的特殊情况。
如果你想避免大的负对数,只改变分子的值(假设从 0 到 1)。不要改变除法结果,因为在大分母的情况下已经有很大的不同了。
【讨论】:
我试过你的代码,但我的情节看起来不同。我是这样画的:for(int i=0; i< pic.total(); i++) Point center = Point(X[i] , Y[i]); circle(plot, center, 1, Scalar(255, 0, 0), 1);
@HadiGhahremanNezhad 这是不同的,因为 OP 打错了,当从imread
返回时,第一个频道是蓝色而不是红色。其次,在绘制绘图时如何处理负值Point(X[i],Y[i])
?最终绘图图像上坐标系的原点在哪里?如果b/g
小于1,则log
返回负值。
@rafix07 你是对的。我更正了负值,情节变得和论文一样。以上是关于OpenCV - 如何计算垫子的对数?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过另一个具有位置(索引)的垫子访问opencv中的矩阵数据