我正在尝试从相机拍摄的照片中提取单个对象。存在没有对象的相机 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/