How to perform image lighting correction with OpenCV?
Asked Answered
P

1

8

I have an image which I grab using a camera. Sometimes, the lighting is uneven in them image. There are some dark shades. This causes incorrect optimal thresholding in EMGU as well as Aforge to process the image for OCR.

This is the image:

enter image description here

This is what I get after thresholding:

enter image description here

How do I correct the lighting? I tried adaptive threshold, gives about the same result. Tried gamma correction too using the code below:

 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);
            }

same result. Please help.

UPDATE: as per Nathancy's suggestion I converted his code to c# for uneven lighting correction and it works:

   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());
Prolongate answered 5/9, 2019 at 11:31 Comment(5)
You need to play with the gamma etc values. 10 may be way over the top. did you see this ? You also may need to apply different settings to different areas of the image.Disengage
Hi @Disengage I tried different gamma values, didnt improve. Tried normalize in EMGU, almost same result.Prolongate
I saw that link you posted, it would work for images with even dark areas. But the image I have has uneven dark/light areas. Do you have any other solution that might work?Prolongate
I would us a combination of contrast first and then gamma. but it really takes some experimentation and doesn't lend itself well to an automated process, at least not without a lot of extra work to separate different areas..Disengage
Why don't you just change the threshold value?Comeau
V
8

Here's an approach:

  • Convert image to grayscale and Gaussian blur to smooth image
  • Adaptive threshold to obtain binary image
  • Perform morphological transformations to smooth image
  • Dilate to enhance text
  • Invert image

After converting to grayscale and blurring, we adaptive threshold

There are small holes and imperfections so we perform a morph close to smooth the image

From we here can optionally dilate to enhance the text

Now we invert the image to get our result

I implemented this method in OpenCV and Python but you can adapt the same strategy into 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()
Vouch answered 5/9, 2019 at 20:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.