【问题标题】:Is there any function equivalent to Matlab's imadjust in OpenCV with C++?在 C++ 的 OpenCV 中是否有任何相当于 Matlab 的 imadjust 的函数?
【发布时间】:2015-10-17 07:05:05
【问题描述】:

我习惯于在 Matlab 中使用imadjust 进行对比度增强。 OpenCV中是否有任何等效功能?

谷歌搜索给出了关于亮度和对比度增强的OpenCV documentation,但它使用可能效率低下的 for 循环。即使我们通过使用Matrix expressions 使其高效,它也不等同于imadjust 所做的。

OpenCV 中是否有任何内置函数或任何有效的任务方法?

我看到了相关的帖子,但不是我上面提到的they link to the OpenCV docthey suggest Histogram Equalization and thresholding。我更喜欢imadjust 到直方图均衡,并且阈值处理似乎并没有像这样执行对比度增强。

对此的任何帮助表示赞赏。

【问题讨论】:

  • 尝试发布一些示例代码和您的预期输出,以便我们提供帮助。
  • @Derman,感谢您的回复。我不能在 OpenCV 中给出示例代码,因为这就是我要找的。但是,您可以在此页面mathworks.com/help/images/ref/imadjust.html 上找到示例结果,这是 imadjust 函数的参考。我期望做与 imadjust 在 Matlab 中所做的相同的事情。希望澄清。
  • 看看equalizeHist
  • @Miki,equalizeHist 使用与 imadjust 不同的直方图均衡。有关差异的更多信息,请参阅此链接 (mathworks.com/matlabcentral/newsreader/view_thread/253503)。它不鼓励使用 histeq 进行处理,甚至我使用 imadjust 观察到了更好的结果。
  • 感谢@Miki 的指导。我会尝试自己编写代码,以便我学到一些东西。如果我仍然失败,我会在这里发表评论。无论如何感谢您提供代码:)

标签: c++ matlab opencv image-processing


【解决方案1】:

OpenCV 中没有内置的解决方案来执行直方图拉伸,但您可以在循环中轻松完成。

imadjust 允许选择上限和下限的容差,或者直接选择边界,因此您需要比简单的 for 循环更多的逻辑。

您可以在实现自己的示例时使用下面的示例作为参考:

#include <opencv2\opencv.hpp>
#include <vector>
#include <algorithm>

using namespace std;
using namespace cv;

void imadjust(const Mat1b& src, Mat1b& dst, int tol = 1, Vec2i in = Vec2i(0, 255), Vec2i out = Vec2i(0, 255))
{
    // src : input CV_8UC1 image
    // dst : output CV_8UC1 imge
    // tol : tolerance, from 0 to 100.
    // in  : src image bounds
    // out : dst image buonds

    dst = src.clone();

    tol = max(0, min(100, tol));

    if (tol > 0)
    {
        // Compute in and out limits

        // Histogram
        vector<int> hist(256, 0);
        for (int r = 0; r < src.rows; ++r) {
            for (int c = 0; c < src.cols; ++c) {
                hist[src(r,c)]++;
            }
        }

        // Cumulative histogram
        vector<int> cum = hist;
        for (int i = 1; i < hist.size(); ++i) {
            cum[i] = cum[i - 1] + hist[i];
        }

        // Compute bounds
        int total = src.rows * src.cols;
        int low_bound = total * tol / 100;
        int upp_bound = total * (100-tol) / 100;
        in[0] = distance(cum.begin(), lower_bound(cum.begin(), cum.end(), low_bound));
        in[1] = distance(cum.begin(), lower_bound(cum.begin(), cum.end(), upp_bound));

    }

    // Stretching
    float scale = float(out[1] - out[0]) / float(in[1] - in[0]);
    for (int r = 0; r < dst.rows; ++r)
    {
        for (int c = 0; c < dst.cols; ++c)
        {
            int vs = max(src(r, c) - in[0], 0);
            int vd = min(int(vs * scale + 0.5f) + out[0], out[1]);
            dst(r, c) = saturate_cast<uchar>(vd);
        }
    }
}

int main()
{
    Mat3b img = imread("path_to_image");

    Mat1b gray;
    cvtColor(img, gray, COLOR_RGB2GRAY);

    Mat1b adjusted;
    imadjust(gray, adjusted);

    // int low_in, high_in, low_out, high_out
    // imadjust(gray, adjusted, 0, Vec2i(low_in, high_in), Vec2i(low_out, high_out));

    return 0;
}

输入图片:

输出调整后的图片:

【讨论】:

  • 您的代码令人印象深刻 - 您的直方图比 STL 算法 std::nth_element 快大约 8 倍。也就是说,当我删除了对 openCV 的所有提及时。我以 950K 时钟而不是 STL 7750K 时钟在 3000 张图像上运行它。
  • 这很好。更简洁的方法是使用cv::calcHist 计算直方图,然后使用std::vector 计算CDF 并找到上限和下限,最后使用cv::threshold 将源钳位在上下限之间,然后@ 987654330@ 和 cv::NORM_MINMAX 进行缩放。这种方法的优点是您可以重用 CV 原语,获得对所有受支持数据类型的支持,并且所有这些都可以推送到 GPU。
【解决方案2】:
【解决方案3】:

你可以试着问这里的人: http://opencv-users.1802565.n2.nabble.com/imadjust-matlab-function-with-stretchlim-OpenCV-implementation-td6253242.html

他的实现基于此: http://www.mathworks.com/matlabcentral/fileexchange/12191-bilateral-filtering

该文件应如下所示,但我不完全确定它是否有效:

void
getOptimalImgAdjustParamsFromHist (IplImage* p_img,unsigned int* p_optminmaxidx, int p_count)
{
  int numBins = 256;
  CvMat* bins = cvCreateMat(1,numBins,CV_8UC1);
  calcHistogram(p_img,bins,numBins);
  int sumlow = 0, sumhigh = 0;
  int low_idx = 0, high_idx = 0;
  for (unsigned int i = 0; i < numBins; i++) {
    float curval = (float) cvGetReal1D (bins, (i));
    sumlow += curval;
    if (sumlow >= p_count) {
      low_idx = i;
      break;
    }
  }
  for (unsigned int i = numBins - 1 ; i >= 0; i--) {
    float curval = (float) cvGetReal1D (bins, (i));
    sumhigh += curval;
    if (sumhigh >= p_count) {
      high_idx = i;
      break;
    }
  }
  cvReleaseMat(&bins);
  p_optminmaxidx[OPTMINIDX] = low_idx;
  p_optminmaxidx[OPTMAXIDX] = high_idx;
}

IplImage *
imageAdjust (IplImage * p_img)
{
  CvSize framesize = cvGetSize (p_img);
  int low_count = round (framesize.width * framesize.height * 0.01);
  unsigned int *optminmaxidx = new unsigned int [2];
  getOptimalImgAdjustParamsFromHist (p_img, optminmaxidx,low_count);
  int range = optminmaxidx[OPTMAXIDX] - optminmaxidx[OPTMINIDX];
  IplImage *adjustedImg = p_img;
  for (int i = 0; i < framesize.height; i++)
    for (int j = 0; j < framesize.width; j++) {
      unsigned int val = (unsigned int) getData (p_img, i, j);
      unsigned int newval = 0;
      if (val <= optminmaxidx[OPTMINIDX]) {
        newval = 0;
        setData (adjustedImg, i, j, (uchar) newval);
      } else if (val >= optminmaxidx[OPTMAXIDX]) {
        newval = 255;
        setData (adjustedImg, i, j, (uchar) newval);
      } else {
        newval =
            (unsigned int) round ((double) (((double) val -
                    (double) optminmaxidx[OPTMINIDX]) * (double) (255.0 /
                    (double) range)));
        setData (adjustedImg, i, j, (uchar) newval);
      }
    }
  delete[]optminmaxidx;
  return adjustedImg;
}

希望对你有帮助。 棒棒哒。

【讨论】:

    猜你喜欢
    • 2020-11-18
    • 2020-03-14
    • 2013-01-27
    • 2015-11-12
    • 2019-11-29
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 2020-04-03
    相关资源
    最近更新 更多