c++ - 找到两个嘈杂的光照变体图像之间的差异(直方图对齐等)

标签 c++ opencv image-processing computer-vision

我正在尝试从相机拍摄的照片中提取单个对象。存在没有对象的相机 View 的图片。相机的焦点不会改变,但当物体在视野中​​时照明会改变。该物体是实心的,但不是恒定的灰色阴影。 Here右边是引用图像的图片,左边是另一个带有对象的图像。图片是单色的。

所有处理都在图像采集之后进行,计算时间不是大问题。算法的精度更为重要。

我在这里发现的大多数问题都是关于两张图片是否相似的问题,但我感兴趣的是找到物体在图像中占据的区域以供后续测量。

到目前为止,我已经尝试了不同的减法组合,然后用阈值对模糊图像进行二值化,但这不是光照不变的。预先将引用图像乘以相对光照差异也不会产生令人满意的结果。如果使用更好的方法来模拟不同的曝光,它可能会起作用。

我也尝试减去 LoG 过滤图像和一些粗略的邻域像素比较,但没有成功。

某种描述符比较应该能够处理,感觉这是一项非常直观的任务,但我正在努力寻找一个好的解决方案。有谁知道我一直缺少的好方法?

提前致谢。


感谢 Franco Callari 的回答,我偶然发现了 histogram matching令我惊讶的是,现成的 OpenCV 函数并未涵盖这一点。由于这似乎是一个常见问题,所以我不妨将我的低效技巧贴在这里,以防有人想使用它。

// Aligns the histogram of the source image to match that of the target image. 
// Both are evaluated in a ROI, not across the whole picture.
// The function assumes 8-bit grayscale images.
static void alignHistogram(Mat alignsource, const Mat& aligntarget, 
    const int rowstart = 500, const int rowend = 700, 
    const int colstart = 0, const int colend = 1000)    
{   
    // 1) Calculate target and source histogram in region of interest
    // 2) Compute the integral of each histogram (cumulative distribution function)
    // 3) Set brightness of each pixel in the source image to the brightness of the target where the CDF values are equal

    Mat ROIsource = alignsource(Range(rowstart, rowend), Range(colstart, colend));
    Mat ROItarget = aligntarget(Range(rowstart, rowend), Range(colstart, colend));
    MatND hist_source, hist_target;

    int bins = 256, int histSize[] = {bins};
    float sranges[] = { 0, 256 };        const float* ranges[] = { sranges };
    int channels[] = {0};
    calcHist( &ROItarget, 1, channels, Mat(), hist_target, 1, histSize, ranges, true, false );
    calcHist( &ROItarget, 1, channels, Mat(), hist_source, 1, histSize, ranges, true, false );

    Mat CDF_target_2d, CDF_source_2d; 
    integral(hist_target, CDF_target_2d);
    integral(hist_source, CDF_source_2d);
    Mat CDF_target = CDF_target_2d.col(1),  CDF_source = CDF_source_2d.col(1);

    // Cycle through source image inefficiently and adjust brightness
    for (int i = 0; i < alignsource.rows; i++)
    {
        for (int j = 0; j < alignsource.cols; j++)
        {
            int source_brightness = alignsource.at<unsigned char>(i, j);
            double cdf_source_value = CDF_source.at<double>(source_brightness);

            int target_brightness = 0;
            while (target_brightness < 256) {
                if (CDF_target.at<double>(target_brightness) > cdf_source_value)
                    break;
                target_brightness++;
            }
            alignsource.at<unsigned char>(i, j) = target_brightness;
        }
    }
}

调整光照有助于更好地初步猜测物体,但不足以获得精确的轮廓,尤其是当背景与物体差异不大或特征丰富时。就我而言此刻得到。

最佳答案

如果相机没有移动,背景也没有改变(如示例照片所示),则全局照明的差异可能(在大多数情况下)是由于两个因素之一 - 具有自动曝光功能的相机当拍摄对象在场景中时,f/stop 或曝光时间的不同选择,或曝光时间窗口内随时间变化的光源(例如灯中的 60Hz 线路嗡嗡声)。如果照明器是闪光灯(并且在两次拍摄之间有足够的时间让闪光灯充电),则后者将被排除在外。

我在上面说“大部分”是因为主体占据了画面的大部分,从它反射的光也会影响全局照明,但在您的情况下,这可能是二阶效应。

您最好的方法可能是更好地控制拍摄 - 至少,禁用相机的自动曝光,使用镇流灯(如果不是频闪灯)。

如果你不能(或另外),你应该从全局直方图对齐开始,而不是均衡。正如其他海报所建议的那样,全局直方图均衡化可能会受到伤害,因为主体的像素值将成为直方图的一部分,而不仅仅是背景。但是,如果相机没有移动,您可以在已知为背景的图像帧区域中预先识别,并在“仅背景”和“有主题”图像中仅从它们中采样直方图。然后,您可以找到动态范围顶部和底部 5% 处的值,并应用全局缩放来匹配它们。

关于c++ - 找到两个嘈杂的光照变体图像之间的差异(直方图对齐等),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15674699/

相关文章:

python - 计算 numpy 数组(图像)特定部分的平均值

php - 如何用php制作照片效果,倾斜图像等?

c++ - 非常量引用绑定(bind)到临时的 Visual Studio 错误?

c++ - 调用构造函数初始化变量

c# - 研究课题 list

c++ - opencv标量中的错误值

opencv - 无法在 OpenCV GPU (CUDA) 中创建过滤器

c++ - openCV 中的 SVM 抛出 "cv::Exception at memory location"

python - 使用python检测图像上的白色背景

python - [报错]在Ubuntu16.04 Python上安装OpenCV 3