Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

551
Visualizações
Algoritmo robusto para detectar iluminación desigual en imágenes [Solo se necesita detección]

Uno de los mayores desafíos en el reconocimiento de texto OCR de tesseract es la iluminación desigual de las imágenes. Necesito un algoritmo que pueda decidir si la imagen contiene iluminaciones desiguales o no.

Imágenes de prueba

Adjunté las imágenes de la imagen no illumination image glare image( white-spotted image) y shadow containing image . Si le damos una imagen al algoritmo, el algoritmo debería dividirse en dos clases como

  1. Sin iluminación desigual: nuestra no illumination image entrará en esta categoría.
  2. Iluminación desigual: nuestra glare image( white-spotted image) , shadow containing image se incluirá en esta categoría.

Imagen sin iluminación - Categoría A

Buena imagen

Imagen de iluminación desigual (imagen deslumbrante (imagen con puntos blancos)) Categoría B

Imagen deslumbrante

Imagen de iluminación desigual (sombra que contiene una imagen) Categoría B

Condiciones de relámpagos irregulares

Acercamiento inicial

  1. Cambiar el espacio de color a HSV

  2. Análisis de histograma del canal de valor de HSV para identificar la iluminación desigual.

En lugar de los primeros dos pasos, podemos usar el canal de brillo percibido en lugar del canal de valor de HSV

  1. Establezca un valor de umbral bajo para obtener la cantidad de píxeles que son menores que el umbral bajo

  2. Establezca un valor de umbral alto para obtener la cantidad de píxeles que son más altos que el umbral alto

  3. porcentaje de valores de píxeles bajos y porcentaje de valores de píxeles altos para detectar condiciones de iluminación desiguales (el umbral de configuración para el porcentaje también)

Pero no pude encontrar grandes similitudes entre las imágenes con iluminación desigual. Acabo de encontrar que hay algunos píxeles que tienen un valor bajo y algunos píxeles tienen un valor alto con el análisis de histograma.

Básicamente, lo que siento es establecer algunos valores de umbral en el bajo y encontrar cuántos píxeles son menores que el umbral bajo y establecer un valor de umbral alto para encontrar cuántos píxeles son mayores que ese umbral. con el recuento de píxeles, ¿podemos llegar a una conclusión para detectar condiciones de iluminación desiguales en las imágenes? Aquí necesitamos finalizar dos valores de umbral y el porcentaje del número de píxeles para llegar a la conclusión.

Análisis de histograma de canal V entre imagen de iluminación buena e irregular

Análisis de histograma de canal V entre imagen de punto de deslumbramiento blanco e imagen de condición de rayo desigual

 def show_hist_v(img_path): img = cv2.imread(img_path) hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) h,s,v = cv2.split(hsv_img) histr =cv2.calcHist(v, [0], None, [255],[0,255]) plt.plot(histr) plt.show() low_threshold =np.count_nonzero(v < 50) high_threshold =np.count_nonzero(v >200) total_pixels = img.shape[0]* img.shape[1] percenet_low =low_threshold/total_pixels*100 percenet_high =high_threshold/total_pixels*100 print("Total Pixels - {}\n Pixels More than 200 - {} \n Pixels Less than 50 - {} \n Pixels percentage more than 200 - {} \n Pixel spercentage less than 50 - {} \n".format(total_pixels,high_threshold,low_threshold,percenet_low,percenet_high)) return total_pixels,high_threshold,low_threshold,percenet_low,percenet_high

Entonces, ¿alguien puede mejorar mi enfoque inicial o dar algo mejor que este enfoque para detectar iluminación desigual en imágenes para casos generales?

Además, probé el brillo percibido en lugar del canal de valor, ya que el canal de valor toma el máximo de valores (b, g, r), el brillo percibido es una buena opción, según creo.

 def get_perceive_brightness( float_img): float_img = np.float64(float_img) # unit8 will make overflow b, g, r = cv2.split(float_img) float_brightness = np.sqrt( (0.241 * (r ** 2)) + (0.691 * (g ** 2)) + (0.068 * (b ** 2))) brightness_channel = np.uint8(np.absolute(float_brightness)) return brightness_channel def show_hist_v(img_path): img = cv2.imread(img_path) v = get_perceive_brightness(img) histr =cv2.calcHist(v, [0], None, [255],[0,255]) plt.plot(histr) plt.show() low_threshold =np.count_nonzero(v < 50) high_threshold =np.count_nonzero(v >200) total_pixels = img.shape[0]* img.shape[1] percenet_low =low_threshold/total_pixels*100 percenet_high =high_threshold/total_pixels*100 print("Total Pixels - {}\n Pixels More than 200 - {} \n Pixels Less than 50 - {} \n Pixels percentage more than 200 - {} \n Pixel spercentage less than 50 - {} \n".format(total_pixels,high_threshold,low_threshold,percenet_low,percenet_high)) return total_pixels,high_threshold,low_threshold,percenet_low,percenet_high

Análisis de histograma del canal de brillo percibido

Análisis de histograma de canal de brillo percibido

Como sugirió Ahmet.

 def get_percentage_of_binary_pixels(img=None, img_path=None): if img is None: if img_path is not None: gray_img = cv2.imread(img_path, 0) else: return "No img or img_path" else: print(img.shape) if len(img.shape) > 2: gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) else: gray_img = img h, w = gray_img.shape guassian_blur = cv2.GaussianBlur(gray_img, (5, 5), 0) thresh_value, otsu_img = cv2.threshold(guassian_blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) cv2.imwrite("binary/{}".format(img_path.split('/')[-1]), otsu_img) black_pixels = np.count_nonzero(otsu_img == 0) # white_pixels = np.count_nonzero(otsu_img == 255) black_pixels_percentage = black_pixels / (h * w) * 100 # white_pixels_percentage = white_pixels / (h * w) * 100 return black_pixels_percentage

cuando obtenemos más del 35% del porcentaje de píxeles negros con binarización otsu, podemos detectar las imágenes de iluminación desigual alrededor del 80 por ciento. Cuando la iluminación se produjo en una pequeña región de la imagen, la detección falla.

Gracias por adelantado

over 4 years ago · Hanz Gallego
4 Respostas
Responde à pergunta

0

¿Por qué no quitas el efecto de rayo de las imágenes?

Por ejemplo:

ingrese la descripción de la imagen aquí

Si queremos leer con pytesseract , la salida será ' \n\f'

  • Pero si quitamos el rayo:

 import cv2 import pytesseract img = cv2.imread('img2.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) smooth = cv2.GaussianBlur(gray, (95, 95), 0) division = cv2.divide(gray, smooth, scale=192)

ingrese la descripción de la imagen aquí

  • Y lea con pytesseract , una parte de la salida será:
 . . . Dosage & use See package insert for compicic information, Instruction: Keep all medicines out of the re. Read the instructions carefully Storage: Store at temperature below 30°C. Protect from Heat, light & moisture. BATCH NO. : 014C003 MFG. DATE - 03-2019 —— EXP. DATE : 03-2021 GENIX Distributed AS Exclusi i : genx PHARMA PRIVATE LIMITED Cevoka Pv 2 A '< » 45-B, Kore ci Karachi-75190, | Pakisier al Pei yaa fans www.genixpharma.com
  • Repita para la última imagen:

ingrese la descripción de la imagen aquí

  • Y lea con pytesseract , una parte de la salida será:
 . . . Dosage & use See package insert for complete prescribing information. Rx Only Instruction: Keep all medicines out of the reach of children. Read the instructions carefully before using. Storage: Store at temperature below 30°C. 5 Protect from Neat, light & moisture. BATCH NO, : 0140003 MFG. DATE : 03-2019 EXP. DATE : 03-2021 Manufactured by: GENI N Exclusively Distributed by: GENIX PHARMA PRIVATE LIMITED Ceyoka (Pvt) Ltd. 44, 45-B, Korangi Creek Road, 55, Negombe Road, Karachi-75190, Pakistan. Peliyagoda, Snianka, www. genixpharma.com

Actualizar

Puede encontrar la parte iluminada utilizando métodos de erode y dilatation .

Resultado:

ingrese la descripción de la imagen aquí

Código:


 import cv2 import imutils import numpy as np from skimage import measure from imutils import contours img = cv2.imread('img2.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (95, 95), 0) thresh = cv2.threshold(blurred, 200, 255, cv2.THRESH_BINARY)[1] thresh = cv2.erode(thresh, None, iterations=2) thresh = cv2.dilate(thresh, None, iterations=4) labels = measure.label(thresh, neighbors=8, background=0) mask = np.zeros(thresh.shape, dtype="uint8") for label in np.unique(labels): if label == 0: continue labelMask = np.zeros(thresh.shape, dtype="uint8") labelMask[labels == label] = 255 numPixels = cv2.countNonZero(labelMask) if numPixels > 300: mask = cv2.add(mask, labelMask) cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) cnts = contours.sort_contours(cnts)[0] for (i, c) in enumerate(cnts): (x, y, w, h) = cv2.boundingRect(c) ((cX, cY), radius) = cv2.minEnclosingCircle(c) cv2.circle(img, (int(cX), int(cY)), int(radius), (0, 0, 255), 3) cv2.putText(img, "#{}".format(i + 1), (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255), 2) cv2.imshow("Image", img) cv2.waitKey(0)

Aunque solo probé con la segunda imagen. Es posible que deba cambiar los parámetros para las otras imágenes.

over 4 years ago · Hanz Gallego Relatório

0

Aquí hay una solución rápida en ImageMagick . Pero se puede implementar fácilmente en Python/OpenCV como se muestra más abajo.

Utilice la normalización de la división.

  • Leer la entrada
  • Opcionalmente convertir a escala de grises
  • Copia la imagen y difumínala
  • Divide la imagen borrosa por el original
  • Guardar los resultados

Aporte:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

 convert 8W0bp.jpg \( +clone -blur 0x13 \) +swap -compose divide -composite x1.png convert ob87W.jpg \( +clone -blur 0x13 \) +swap -compose divide -composite x2.png convert HLJuA.jpg \( +clone -blur 0x13 \) +swap -compose divide -composite x3.png

Resultados:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

En Python/OpenCV:

 import cv2 import numpy as np import skimage.filters as filters # read the image img = cv2.imread('8W0bp.jpg') #img = cv2.imread('ob87W.jpg') #img = cv2.imread('HLJuA.jpg') # convert to gray gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # blur smooth = cv2.GaussianBlur(gray, (33,33), 0) # divide gray by morphology image division = cv2.divide(gray, smooth, scale=255) # sharpen using unsharp masking sharp = filters.unsharp_mask(division, radius=1.5, amount=2.5, multichannel=False, preserve_range=False) sharp = (255*sharp).clip(0,255).astype(np.uint8) # save results cv2.imwrite('8W0bp_division.jpg',division) cv2.imwrite('8W0bp_division_sharp.jpg',sharp) #cv2.imwrite('ob87W_division.jpg',division) #cv2.imwrite('ob87W_division_sharp.jpg',sharp) #cv2.imwrite('HLJuA_division.jpg',division) #cv2.imwrite('HLJuA_division_sharp.jpg',sharp) # show results cv2.imshow('smooth', smooth) cv2.imshow('division', division) cv2.imshow('sharp', sharp) cv2.waitKey(0) cv2.destroyAllWindows()

Resultados:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

over 4 years ago · Hanz Gallego Relatório

0

Sugiero usar el truco de la división para separar el texto del fondo y luego calcular las estadísticas solo en el fondo. Después de establecer algunos umbrales razonables, es fácil crear un clasificador para la iluminación.

 def get_image_stats(img_path, lbl): img = cv2.imread(img_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (25, 25), 0) no_text = gray * ((gray/blurred)>0.99) # select background only no_text[no_text<10] = no_text[no_text>20].mean() # convert black pixels to mean value no_bright = no_text.copy() no_bright[no_bright>220] = no_bright[no_bright<220].mean() # disregard bright pixels print(lbl) std = no_bright.std() print('STD:', std) bright = (no_text>220).sum() print('Brigth pixels:', bright) plt.figure() plt.hist(no_text.reshape(-1,1), 25) plt.title(lbl) if std>25: print("!!! Detected uneven illumination") if no_text.mean()<200 and bright>8000: print("!!! Detected glare")

Esto resulta en:

 good_img STD: 11.264569863071165 Brigth pixels: 58 glare_img STD: 15.00149131296984 Brigth pixels: 15122 !!! Detected glare uneven_img STD: 57.99510339944441 Brigth pixels: 688 !!! Detected uneven illumination

ingrese la descripción de la imagen aquí

Ahora analicemos los histogramas y apliquemos algo de sentido común. Esperamos que el fondo sea parejo y tenga poca variación, como es el caso de "good_img". Si tiene una varianza alta, entonces su desviación estándar sería alta y es el caso de un brillo desigual. En la imagen inferior puedes ver 3 picos (más pequeños) que son responsables de las 3 áreas iluminadas diferentes. El pico más grande en el medio es el resultado de establecer todos los píxeles negros en el valor medio. Creo que es seguro llamar a las imágenes con STD por encima de 25 como caso de "iluminación desigual".

Es fácil detectar una gran cantidad de píxeles brillantes cuando hay deslumbramiento (ver imagen a la derecha). La imagen deslumbrada parece una buena imagen, además del punto caliente. Establecer el umbral de píxeles brillantes en algo así como 8000 (1,5% del tamaño total de la imagen) debería ser bueno para detectar este tipo de imágenes. Existe la posibilidad de que el fondo sea muy brillante en todas partes, por lo que si la media de píxeles no_text es superior a 200, entonces es el caso y no hay necesidad de detectar puntos calientes.

over 4 years ago · Hanz Gallego Relatório

0

Aquí mi canalización:

 %matplotlib inline import numpy as np import cv2 from matplotlib import pyplot as plt from scipy.signal import find_peaks

Yo uso las funciones:

 def get_perceived_brightness( float_img): float_img = np.float64(float_img) # unit8 will make overflow b, g, r = cv2.split(float_img) float_brightness = np.sqrt((0.241 * (r ** 2)) + (0.691 * (g ** 2)) + (0.068 * (b ** 2))) brightness_channel = np.uint8(np.absolute(float_brightness)) return brightness_channel # from: https://stackoverflow.com/questions/46300577/find-locale-minimum-in-histogram-1d-array-python def smooth(x,window_len=11,window='hanning'): if x.ndim != 1: raise ValueError("smooth only accepts 1 dimension arrays.") if x.size < window_len: raise ValueError("Input vector needs to be bigger than window size.") if window_len<3: return x if not window in ['flat', 'hanning', 'hamming', 'bartlett', 'blackman']: raise ValueError("Window is on of 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'") s=np.r_[x[window_len-1:0:-1],x,x[-2:-window_len-1:-1]] if window == 'flat': #moving average w=np.ones(window_len,'d') else: w=eval('np.'+window+'(window_len)') y=np.convolve(w/w.sum(),s,mode='valid') return y

cargo la imagen

 image_file_name = 'im3.jpg' image = cv2.imread(image_file_name) # image category category = 0 # gray convertion image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) height = image.shape[0] width = image.shape[1]

Primer examen. ¿La imagen tiene grandes puntos blancos?

 # First test. Does the image have any big white spots? saturation_thresh = 250 raw_saturation_region = cv2.threshold(image_gray, saturation_thresh, 255, cv2.THRESH_BINARY)[1] num_raw_saturation_regions, raw_saturation_regions,stats, _ = cv2.connectedComponentsWithStats(raw_saturation_region) # index 0 is the background -> to remove area_raw_saturation_regions = stats[1:,4] min_area_bad_spot = 1000 # this can be calculated as percentage of the image area if (np.max(area_raw_saturation_regions) > min_area_bad_spot): category = 2 # there is at least one spot

El resultado para la imagen normal: ingrese la descripción de la imagen aquí

El resultado de la imagen con manchas: ingrese la descripción de la imagen aquí

El resultado de la imagen con sombras: ingrese la descripción de la imagen aquí

Si la imagen pasa la primera prueba, proceso la segunda prueba. ¿La imagen es oscura?

 # Second test. Is the image dark? min_mean_intensity = 60 if category == 0 : mean_intensity = np.mean(image_gray) if (mean_intensity < min_mean_intensity): category = 3 # dark image

Si la imagen pasa también la segunda prueba, proceso la tercera prueba. ¿La imagen está uniformemente iluminada?

 window_len = 15 # odd number delay = int((window_len-1)/2) # delay is the shift introduced from the smoothing. It's half window_len # for example if the window_len is 15, the delay is 7 # infact hist.shape = 256 and smooted_hist.shape = 270 (= 256 + 2*delay) if category == 0 : perceived_brightness = get_perceived_brightness(image) hist,bins = np.histogram(perceived_brightness.ravel(),256,[0,256]) # smoothed_hist is shifted from the original one smoothed_hist = smooth(hist,window_len) # smoothed histogram syncronized with the original histogram sync_smoothed_hist = smoothed_hist[delay:-delay] # if number the peaks with: # 20<bin<250 # prominance >= mean histogram value # the image could have shadows (but it could have also a background with some colors) mean_hist = int(height*width / 256) peaks, _ = find_peaks(sync_smoothed_hist, prominence=mean_hist) selected_peaks = peaks[(peaks > 20) & (peaks < 250)] if (selected_peaks.size>1) : category = 4 # there are shadows

El histograma para la imagen normal: ingrese la descripción de la imagen aquí

El histograma de la imagen con manchas: ingrese la descripción de la imagen aquí

El histograma de la imagen con sombras: ingrese la descripción de la imagen aquí

Si la imagen pasa todas las pruebas, entonces es normal.

 # all tests are passed. The image is ok if (category == 0) : category=1 # the image is ok
over 4 years ago · Hanz Gallego Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda