如何使用OpenCV进行图像光照校正?

8
我有一张图像,是通过相机获取的。有时候,图像的光照不均,存在一些暗色调。这会导致EMGU和Aforge在对该图像进行OCR处理时产生不正确的最优阈值。
这是该图像:

enter image description here

这是在阈值处理后得到的结果:

enter image description here

我该如何纠正照明?我尝试了自适应阈值,但结果差不多。我还尝试了使用以下代码进行伽马校正:

 ImageAttributes attributes = new ImageAttributes();
            attributes.SetGamma(10);

            // Draw the image onto the new bitmap
            // while applying the new gamma value.
            System.Drawing.Point[] points =
   {
    new System.Drawing.Point(0, 0),
    new System.Drawing.Point(image.Width, 0),
    new System.Drawing.Point(0, image.Height),
   };
            Rectangle rect =
                new Rectangle(0, 0, image.Width, image.Height);

            // Make the result bitmap.
            Bitmap bm = new Bitmap(image.Width, image.Height);
            using (Graphics gr = Graphics.FromImage(bm))
            {
                gr.DrawImage(HSICONV.Bitmap, points, rect,
                    GraphicsUnit.Pixel, attributes);
            }

同样的结果。请帮忙。 更新: 根据 Nathancy 的建议,我将他的代码转换为 C# 用于不均匀照明校正,它有效。
   Image<Gray, byte> smoothedGrayFrame = grayImage.PyrDown();
                smoothedGrayFrame = smoothedGrayFrame.PyrUp();
                //canny
                Image<Gray, byte> cannyFrame = null;

                cannyFrame = smoothedGrayFrame.Canny(50, 50);
                //smoothing

                grayImage = smoothedGrayFrame;
                //binarize
                Image<Gray, byte> grayout = grayImage.Clone();
                CvInvoke.AdaptiveThreshold(grayImage, grayout, 255, AdaptiveThresholdType.GaussianC, ThresholdType.BinaryInv, Convert.ToInt32(numericmainthreshold.Value) + Convert.ToInt32(numericmainthreshold.Value) % 2 + 1, 1.2d);
                grayout._Not();
                Mat kernelCl = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new System.Drawing.Point(-1, -1));
                CvInvoke.MorphologyEx(grayout, grayout, MorphOp.Close, kernelCl, new System.Drawing.Point(-1, -1), 1, BorderType.Default, new MCvScalar());

你需要调整伽马等值。10可能过于夸张了。你看到这个了吗?(链接)你也许需要对图像的不同区域应用不同的设置。 - TaW
嗨@TaW,我尝试了不同的伽马值,但没有改善。在EMGU中尝试了归一化,结果几乎相同。 - Roshan
我看到你发布的链接,它适用于甚至有暗区的图像。但是我手头的图像有不均匀的暗/亮区域。你有其他可能有效的解决方案吗? - Roshan
我会先使用对比度,然后再使用伽马校正的组合。但这确实需要一些试验,并且不适合自动化处理,至少不是在分离不同区域需要进行大量额外工作的情况下。 - TaW
为什么不直接改变阈值呢? - Rotem
1个回答

8
以下是一种方法:
  • 将图像转换为灰度并进行高斯模糊,以平滑图像
  • 自适应阈值获取二进制图像
  • 执行形态学变换以平滑图像
  • 膨胀以增强文本
  • 反转图像

在转换为灰度和模糊之后,我们进行自适应阈值处理

由于存在小孔和缺陷,因此我们执行形态闭合以使图像平滑

从这里开始,我们可以选择进行膨胀以增强文本

现在我们反转图像以获取结果

我在OpenCV和Python中实现了这种方法,但您也可以将相同的策略适应到C#上。
import cv2

image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, \
         cv2.THRESH_BINARY_INV,9,11)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
dilate = cv2.dilate(close, kernel, iterations=1)
result = 255 - dilate 

cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('dilate', dilate)
cv2.imshow('result', result)
cv2.waitKey()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接