OpenCV - 如何计算垫子的对数?

Posted

技术标签:

【中文标题】OpenCV - 如何计算垫子的对数?【英文标题】:OpenCV - How to claculate logarithm of a Mat? 【发布时间】:2020-02-27 14:25:16 【问题描述】:

我正在尝试根据这个公式计算两个向量 XY

地点:

我决定使用两个 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)。

我不想要大的负数,因为稍后我要将XY 的所有像素值相加,总和变为-nan

我确定我取对数的方式有问题,因为结果是错误的。我应该如何以正确的方式做到这一点?


例如,对于这张图片:

XY 值应该是这样的(蓝点):

但就我而言,它们是这样的:

这些是垫子:


根据下面的答案,我将这个添加到代码中以避免零除:

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&lt; 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中的矩阵数据

视频文件中的垫子数组 - opencv

从 OpenCV 3 中的 VideoCapture 获取垫子

通过引用传递一个垫子对象 OpenCv

OpenCV-计算自然对数cv::log

openCV:将垫子保存到矢量<vector<int>>