Corrección de iluminación simple en imágenes openCV c ++

Tengo algunas fotos en color y la iluminación no es regular en las fotos: un lado de la imagen es más shiny que el otro lado.

Me gustaría resolver este problema corrigiendo la iluminación. Creo que el contraste local me ayudará, pero no sé cómo 🙁

¿Podrías ayudarme con un código o una tubería?

Convierta la imagen RGB en espacio de color Lab (por ejemplo, cualquier espacio de color con un canal de luminancia funcionará bien), luego aplique ecualización de histogtwig adaptativo al canal L. Finalmente convierte el Lab resultante a RGB.

Lo que desea es el algoritmo CLAHE (Contraste Limitado de Ecualización Adaptativa Adaptable) de OpenCV. Sin embargo, hasta donde sé, no está documentado. Hay un ejemplo en python . Puede leer sobre CLAHE en Graphics Gems IV, pp474-485

Aquí hay un ejemplo de CLAHE en acción: enter image description here

Y aquí está el C ++ que produjo la imagen de arriba, basada en http://answers.opencv.org/question/12024/use-of-clahe/ , pero extendida para el color.

#include  #include  // std::vector int main(int argc, char** argv) { // READ RGB color image and convert it to Lab cv::Mat bgr_image = cv::imread("image.png"); cv::Mat lab_image; cv::cvtColor(bgr_image, lab_image, CV_BGR2Lab); // Extract the L channel std::vector lab_planes(3); cv::split(lab_image, lab_planes); // now we have the L image in lab_planes[0] // apply the CLAHE algorithm to the L channel cv::Ptr clahe = cv::createCLAHE(); clahe->setClipLimit(4); cv::Mat dst; clahe->apply(lab_planes[0], dst); // Merge the the color planes back into an Lab image dst.copyTo(lab_planes[0]); cv::merge(lab_planes, lab_image); // convert back to RGB cv::Mat image_clahe; cv::cvtColor(lab_image, image_clahe, CV_Lab2BGR); // display the results (you might also want to see lab_planes[0] before and after). cv::imshow("image original", bgr_image); cv::imshow("image CLAHE", image_clahe); cv::waitKey(); } 

La respuesta proporcionada por Bull es la mejor que he encontrado hasta ahora. Lo he estado usando para. Aquí está el código python para el mismo:

 import cv2 #-----Reading the image----------------------------------------------------- img = cv2.imread('Dog.jpg', 1) cv2.imshow("img",img) #-----Converting image to LAB Color model----------------------------------- lab= cv2.cvtColor(img, cv2.COLOR_BGR2LAB) cv2.imshow("lab",lab) #-----Splitting the LAB image to different channels------------------------- l, a, b = cv2.split(lab) cv2.imshow('l_channel', l) cv2.imshow('a_channel', a) cv2.imshow('b_channel', b) #-----Applying CLAHE to L-channel------------------------------------------- clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) cl = clahe.apply(l) cv2.imshow('CLAHE output', cl) #-----Merge the CLAHE enhanced L-channel with the a and b channel----------- limg = cv2.merge((cl,a,b)) cv2.imshow('limg', limg) #-----Converting image from LAB Color model to RGB model-------------------- final = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR) cv2.imshow('final', final) #_____END_____# 

Basado en el gran ejemplo de C ++ escrito por Bull , pude escribir este método para Android.

He sustituido “Core.extractChannel” para “Core.split”. Esto evita un problema conocido de pérdida de memoria .

 public void applyCLAHE(Mat srcArry, Mat dstArry) { //Function that applies the CLAHE algorithm to "dstArry". if (srcArry.channels() >= 3) { // READ RGB color image and convert it to Lab Mat channel = new Mat(); Imgproc.cvtColor(srcArry, dstArry, Imgproc.COLOR_BGR2Lab); // Extract the L channel Core.extractChannel(dstArry, channel, 0); // apply the CLAHE algorithm to the L channel CLAHE clahe = Imgproc.createCLAHE(); clahe.setClipLimit(4); clahe.apply(channel, channel); // Merge the the color planes back into an Lab image Core.insertChannel(channel, dstArry, 0); // convert back to RGB Imgproc.cvtColor(dstArry, dstArry, Imgproc.COLOR_Lab2BGR); // Temporary Mat not reused, so release from memory. channel.release(); } } 

Y llámalo así:

 public Mat onCameraFrame(CvCameraViewFrame inputFrame){ Mat col = inputFrame.rgba(); applyCLAHE(col, col);//Apply the CLAHE algorithm to input color image. return col; } 

También puede usar la ecualización adaptable del histogtwig,

 from skimage import exposure img_adapteq = exposure.equalize_adapthist(img, clip_limit=0.03) 

Puedes probar el siguiente código:

 #include "opencv2/opencv.hpp" #include  using namespace std; using namespace cv; int main(int argc, char** argv) { cout<<"Usage: ./executable input_image output_image \n"; if(argc!=3) { return 0; } int filterFactor = 1; Mat my_img = imread(argv[1]); Mat orig_img = my_img.clone(); imshow("original",my_img); Mat simg; cvtColor(my_img, simg, CV_BGR2GRAY); long int N = simg.rows*simg.cols; int histo_b[256]; int histo_g[256]; int histo_r[256]; for(int i=0; i<256; i++){ histo_b[i] = 0; histo_g[i] = 0; histo_r[i] = 0; } Vec3b intensity; for(int i=0; i(i,j); histo_b[intensity.val[0]] = histo_b[intensity.val[0]] + 1; histo_g[intensity.val[1]] = histo_g[intensity.val[1]] + 1; histo_r[intensity.val[2]] = histo_r[intensity.val[2]] + 1; } } for(int i = 1; i<256; i++){ histo_b[i] = histo_b[i] + filterFactor * histo_b[i-1]; histo_g[i] = histo_g[i] + filterFactor * histo_g[i-1]; histo_r[i] = histo_r[i] + filterFactor * histo_r[i-1]; } int vmin_b=0; int vmin_g=0; int vmin_r=0; int s1 = 3; int s2 = 3; while(histo_b[vmin_b+1] <= N*s1/100){ vmin_b = vmin_b +1; } while(histo_g[vmin_g+1] <= N*s1/100){ vmin_g = vmin_g +1; } while(histo_r[vmin_r+1] <= N*s1/100){ vmin_r = vmin_r +1; } int vmax_b = 255-1; int vmax_g = 255-1; int vmax_r = 255-1; while(histo_b[vmax_b-1]>(N-((N/100)*s2))) { vmax_b = vmax_b-1; } if(vmax_b < 255-1){ vmax_b = vmax_b+1; } while(histo_g[vmax_g-1]>(N-((N/100)*s2))) { vmax_g = vmax_g-1; } if(vmax_g < 255-1){ vmax_g = vmax_g+1; } while(histo_r[vmax_r-1]>(N-((N/100)*s2))) { vmax_r = vmax_r-1; } if(vmax_r < 255-1){ vmax_r = vmax_r+1; } for(int i=0; i(i,j); if(intensity.val[0]vmax_b){ intensity.val[0]=vmax_b; } if(intensity.val[1]vmax_g){ intensity.val[1]=vmax_g; } if(intensity.val[2]vmax_r){ intensity.val[2]=vmax_r; } my_img.at(i,j) = intensity; } } for(int i=0; i(i,j); intensity.val[0] = (intensity.val[0] - vmin_b)*255/(vmax_b-vmin_b); intensity.val[1] = (intensity.val[1] - vmin_g)*255/(vmax_g-vmin_g); intensity.val[2] = (intensity.val[2] - vmin_r)*255/(vmax_r-vmin_r); my_img.at(i,j) = intensity; } } // sharpen image using "unsharp mask" algorithm Mat blurred; double sigma = 1, threshold = 5, amount = 1; GaussianBlur(my_img, blurred, Size(), sigma, sigma); Mat lowContrastMask = abs(my_img - blurred) < threshold; Mat sharpened = my_img*(1+amount) + blurred*(-amount); my_img.copyTo(sharpened, lowContrastMask); imshow("New Image",sharpened); waitKey(0); Mat comp_img; hconcat(orig_img, sharpened, comp_img); imwrite(argv[2], comp_img); } 

Consulte aquí para más detalles.