Ho scritto qualche codice Python (mi dispiace non C++) che consentirà la soglia mascherata adattiva. Non è molto veloce, ma fa quello che vuoi, e potresti essere in grado di usarlo come base per il codice C++. Funziona come segue:
- Imposta i pixel mascherati nell'immagine a zero.
- Determina il numero di vicini non mascherati all'interno del blocco di convoluzione per ciascun pixel.
- Esegue una convoluzione e la media in base al numero di vicini non mascherati all'interno del blocco. Questo produce il valore medio all'interno di un blocco di quartiere dei pixel.
- Soglie, confrontando l'immagine con i valori medi delle vicinanze,
mean_conv
- Aggiunge la parte mascherata (senza soglia) dell'immagine.
Le immagini mostrano, l'immagine iniziale, la maschera, l'immagine elaborata finale.
Ecco il codice:
import cv
import numpy
from scipy import signal
def thresh(a, b, max_value, C):
return max_value if a > b - C else 0
def mask(a,b):
return a if b > 100 else 0
def unmask(a,b,c):
return b if c > 100 else a
v_unmask = numpy.vectorize(unmask)
v_mask = numpy.vectorize(mask)
v_thresh = numpy.vectorize(thresh)
def block_size(size):
block = numpy.ones((size, size), dtype='d')
block[(size - 1)/2, (size - 1)/2] = 0
return block
def get_number_neighbours(mask,block):
'''returns number of unmasked neighbours of every element within block'''
mask = mask/255.0
return signal.convolve2d(mask, block, mode='same', boundary='symm')
def masked_adaptive_threshold(image,mask,max_value,size,C):
'''thresholds only using the unmasked elements'''
block = block_size(size)
conv = signal.convolve2d(image, block, mode='same', boundary='symm')
mean_conv = conv/get_number_neighbours(mask,block)
return v_thresh(image, mean_conv, max_value,C)
image = cv.LoadImageM("image.png", cv.CV_LOAD_IMAGE_GRAYSCALE)
mask = cv.LoadImageM("mask.png", cv.CV_LOAD_IMAGE_GRAYSCALE)
#change the images to numpy arrays
original_image = numpy.asarray(image)
mask = numpy.asarray(mask)
# Masks the image, by removing all masked pixels.
# Elements for mask > 100, will be processed
image = v_mask(original_image, mask)
# convolution parameters, size and C are crucial. See discussion in link below.
image = masked_adaptive_threshold(image,mask,max_value=255,size=7,C=5)
# puts the original masked off region of the image back
image = v_unmask(original_image, image, mask)
#change to suitable type for opencv
image = image.astype(numpy.uint8)
#convert back to cvmat
image = cv.fromarray(image)
cv.ShowImage('image', image)
#cv.SaveImage('final.png',image)
cv.WaitKey(0)
Dopo aver scritto questo ho trovato this great link che ha una buona spiegazione con un sacco di esempi di immagini, ho usato la loro immagine di testo per l'esempio precedente.
Nota. Le maschere di Numpy non sembrano essere rispettate da scipy signal.convolve2d()
, quindi le soluzioni alternative sopra descritte erano necessarie.
La ringrazio molto per la risposta. Sto indagando sul tuo suggerimento. Quentin –
@Quentin Geissmann - Hai funzionato nel tuo codice C++? – fraxel
Penso di aver capito come implementarlo senza renderlo molto lento ... Ma non ancora implementato. :) grazie –