2012-03-23 13 views
7

Sto scrivendo un piccolo programma in C++ usando l'API OpenCV-2.3. Ho un problema nell'elaborazione di una soglia adattativa utilizzando una maschera non rettangolare.Utilizzo di una maschera con una soglia adattativa?

Finora, stavo eseguendo la soglia adattativa sull'intera immagine e mascherandola in seguito. Mi rendo conto che, nel mio caso, si è trattato di un errore poiché i pixel mascherati sarebbero stati utilizzati per calcolare la soglia dei miei pixel di interesse (mentre voglio semplicemente escludere il primo dall'analisi) ... Tuttavia, a differenza di funzioni come come cv :: norm, cv :: adaptiveThreshold non sembra supportare esplicitamente una maschera.

Conosci qualche soluzione o soluzione ovvia? Grazie mille per i vostri suggerimenti, Quentin

risposta

3

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:

  1. Imposta i pixel mascherati nell'immagine a zero.
  2. Determina il numero di vicini non mascherati all'interno del blocco di convoluzione per ciascun pixel.
  3. 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.
  4. Soglie, confrontando l'immagine con i valori medi delle vicinanze, mean_conv
  5. Aggiunge la parte mascherata (senza soglia) dell'immagine.

enter image description here

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.

+0

La ringrazio molto per la risposta. Sto indagando sul tuo suggerimento. Quentin –

+0

@Quentin Geissmann - Hai funzionato nel tuo codice C++? – fraxel

+0

Penso di aver capito come implementarlo senza renderlo molto lento ... Ma non ancora implementato. :) grazie –

3

Secondo i vostri consigli, e dopo aver letto il vostro collegamento ho scritto questa piccola funzione C++: Questo è solo 1.5 più lento della soglia adattiva, ma probabilmente posso migliorarlo.

void adaptiveThresholdMask(const cv::Mat src,cv::Mat &dst, double maxValue,  cv::Mat mask, int thresholdType, int blockSize, double C){ 
cv::Mat img, invertMask, noN, conv,kernel(cv::Size(blockSize,blockSize),CV_32F); 

/* Makes a image copy of the source image*/ 
src.copyTo(img); 

/* Negates the mask*/ 
cv::bitwise_not(mask,invertMask); 

/* Sets to 0 all pixels out of the mask*/ 
img = img-invertMask; 
/* The two following tasks are both intensive and 
* can be done in parallel (here with OpenMP)*/ 
#pragma omp parallel sections 
{ 
    { 
     /* Convolves "img" each pixels takes the average value of all the pixels in blocksize*/ 
     cv::blur(img,conv,cv::Size(blockSize,blockSize)); 
    } 
    #pragma omp section 
    { 
     /* The result of bluring "mask" is proportional to the number of neighbours */ 
     cv::blur(mask,noN,cv::Size(blockSize,blockSize)); 
    } 
} 

/* Makes a ratio between the convolved image and the number of 
* neighbours and subtracts from the original image*/ 
if(thresholdType==cv::THRESH_BINARY_INV){ 
    img=255*(conv/noN)-img; 
    } 
else{ 
    img=img-255*(conv/noN); 
    } 

/* Thresholds by the user defined C*/ 
cv::threshold(img,dst,C,maxValue,cv::THRESH_BINARY); 

/* We do not want to keep pixels outside of the mask*/ 
cv::bitwise_and(mask,dst,dst); 

} 

Grazie ancora

+0

nice one :) Penso di poter velocizzare molto il mio codice Python, cercherò di aggirarlo ad un certo punto .. – fraxel

+0

Non capisco questa soluzione. Puoi approfondire come funziona questa versione di accelerazione? Ho provato a portarlo su opencv-python ma senza successo – pzo

+0

È una soluzione molto bella e super veloce (testata in Python), anche se diventa un po 'imprecisa quando l'immagine è molto scura, perché poi si gratta la risoluzione intera a causa di le operazioni di sfocatura. – letmaik

Problemi correlati