2015-06-30 10 views
9

Sto cercando di rimuovere lo sfondo di alcune immagini, modificando alcuni valori e utilizzando alcuni metodi come morphologyEx mi dà un risultato accettabile ma alcuni buchi rimangono, in quest'ultimo caso i fori non riempiono anche l'iterazione su ogni contorno e disegnandolo con -1. Posso vedere che l'immagine di soglia è veramente buono, rendendo l'intera forma con le linee, ma non so come continuare ...OpenCV rimuovi sfondo

Aggiornamento ho cambiato il mio codice in modo da ottenere risultati migliori, ma io sto ancora ottenendo dei buchi ... Se potessi riempire questi buchi, la sceneggiatura sarebbe perfetta.

def get_contrasted(image, type="dark", level=3): 
    maxIntensity = 255.0 # depends on dtype of image data 
    phi = 1 
    theta = 1 

    if type == "light": 
     newImage0 = (maxIntensity/phi)*(image/(maxIntensity/theta))**0.5 
     newImage0 = array(newImage0,dtype=uint8) 
     return newImage0 
    elif type == "dark": 
     newImage1 = (maxIntensity/phi)*(image/(maxIntensity/theta))**level 
     newImage1 = array(newImage1,dtype=uint8) 

     return newImage1 

def sharp(image, level=3): 
    f = cv2.GaussianBlur(image, (level,level), level) 
    f = cv2.addWeighted(image, 1.5, f, -0.5, 0) 
    return f 

original_image = imread('imagen.jpg') 
# 1 Convert to gray & Normalize 
gray_img = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY) 
gray_img = sharp(get_contrasted(gray_img)) 
gray_img = normalize(gray_img, None, 0, 255, NORM_MINMAX, CV_8UC1) 
imshow("Gray", gray_img) 

# 2 Find Threshold 
gray_blur = cv2.GaussianBlur(gray_img, (7, 7), 0) 
adapt_thresh_im = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 1) 
max_thresh, thresh_im = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) 
thresh = cv2.bitwise_or(adapt_thresh_im, thresh_im) 

# 3 Dilate 
gray = cv2.Canny(thresh, 88, 400, apertureSize=3) 
gray = cv2.dilate(gray, None, iterations=8) 
gray = cv2.erode(gray, None, iterations=8) 
imshow("Trheshold", gray) 

# 4 Flood 
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 
contour_info = [] 
for c in contours: 
    contour_info.append((
     c, 
     cv2.isContourConvex(c), 
     cv2.contourArea(c), 
    )) 
contour_info = sorted(contour_info, key=lambda c: c[2], reverse=True) 
max_contour = contour_info[0] 
holes = np.zeros(gray_img.shape, np.uint8) 
drawContours(holes, max_contour, 0, 255, -1) 
imshow("Holes", holes) 

mask = cv2.GaussianBlur(holes, (15, 15), 0) 
mask = np.dstack([mask] * 3) # Create 3-channel alpha mask 

mask = mask.astype('float32')/255.0 # Use float matrices, 
img = original_image.astype('float32')/255.0 # for easy blending 
masked = (mask * img) + ((1 - mask) * (0,0,1)) # Blend 
masked = (masked * 255).astype('uint8') 

imshow("Maked", masked) 
waitKey() 

0 originale

enter image description here

1 Soglia

enter image description here

2 fori

enter image description here

3 Immagine finale

enter image description here

+0

Il codice non è un codice Python valido. Si prega di inviare il codice senza errori di sintassi (vale a dire, un codice che è in grado di eseguire). – boardrider

+0

Parentesi mancante, ora aggiornata. –

+0

Per prima cosa dovresti cercare alcuni tutorial opencv sul mascheramento. Inoltre, guarda questo: http://stackoverflow.com/questions/18710428/how-to-remove-background-image-with-opencv –

risposta

8

iterativamente eseguire una chiusura morfologica della vostra immagine fori utilizzando un kernel di dimensioni crescenti. Prima di fare ciò, suggerisco di ridimensionare l'immagine dei buchi (usando l'interpolazione più vicina) in modo da non dover usare grossi kernel. Nel seguente codice (C++), ho ridimensionato l'immagine dei fori al 25% delle sue dimensioni originali.

Per ridurre gli effetti sui bordi, aggiungere un bordo costante di zero utilizzando copyMakeBorder prima di applicare la chiusura iterativa. Come stiamo usando 15 iterazioni qui, fare il bordo intorno all'immagine più grande di 15.

Quindi i passaggi sono

  • Ridimensionare l'immagine fori
  • aggiungere un bordo a zero
  • iterativamente chiudere l'immagine con un kernel di dimensioni crescenti
  • Rimuovere il bordo
  • Ora abbiamo una piccola maschera. Ridimensiona questa maschera alla dimensione dell'immagine originale

Il codice è in C++. Non ho molta familiarità con Python.

// read the image and the holes 
    Mat im = imread("koAl2.jpg"); 
    Mat holes = imread("GuICX.jpg", 0); 
    // resize 
    Mat small, bordered; 
    resize(holes, small, Size(), .25, .25); 
    // add a zero border 
    int b = 20; 
    copyMakeBorder(small, bordered, b, b, b, b, BORDER_CONSTANT, Scalar(0)); 
    // close 
    for (int i = 1; i < 15; i++) 
    { 
     Mat kernel = getStructuringElement(MORPH_ELLIPSE, cv::Size(2*i+1, 2*i+1)); 
     morphologyEx(bordered, bordered, MORPH_CLOSE, kernel, Point(-1, -1), 1); 
    } 
    // remove border 
    Mat mask = bordered(Rect(b, b, small.cols, small.rows)); 
    // resize the mask 
    Mat largeMask; 
    resize(mask, largeMask, Size(im.cols, im.rows)); 
    // the foreground 
    Mat fg; 
    im.copyTo(fg, largeMask); 

L'uscita (non in scala originale) guarda bene, tranne che ci vuole la regione fondo in fondo, come in primo piano.

enter image description here

+1

Non riesco a farlo funzionare su Python, ci sono due cose che non posso convertire in Python: 1: 'bordered' è appena diventato un metodo? Quando? 'delimitato (Rect (b, b, small.cols, small.rows))' e cosa è 'Rect'? 2: 'ridimensiona (fori, piccolo, Dimensione(), .25, .25)' Non ho un oggetto 'Size()', immagino che questa sia una Tupla ??, ma non posso usare una tupla vuota '()' 3: 'morfologiaEx (confinato, confinato, MORPH_CLOSE, kernel, Point (-1, -1), 1)' diventa 'bordered = cv2.morphologyEx (confinato, cv2.MORPH_CLOSE, kernel, (-1, -1), 1) 'in python ma errore:' nuovo formato getargs di stile ma l'argomento non è una tupla' –

+0

'Maschera mat = bordata (Rect (b, b, small.cols, small.rows)) ; 'estrae la ROI specificata in maschera. È un operatore della classe Mat. Sarai in grado di farlo funzionare se ti concentri sulla descrizione che ho dato piuttosto che provare a fare una mappatura uno-a-uno del codice C++ in Python. Ho aggiunto il codice sperando che avrebbe reso la descrizione più chiara. – dhanushka

4

@ metodo di Dhanushka funziona bene.Ecco la mia versione divinatorio:

def get_holes(image, thresh): 
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) 

    im_bw = cv.threshold(gray, thresh, 255, cv.THRESH_BINARY)[1] 
    im_bw_inv = cv.bitwise_not(im_bw) 

    contour, _ = cv.findContours(im_bw_inv, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE) 
    for cnt in contour: 
     cv.drawContours(im_bw_inv, [cnt], 0, 255, -1) 

    nt = cv.bitwise_not(im_bw) 
    im_bw_inv = cv.bitwise_or(im_bw_inv, nt) 
    return im_bw_inv 


def remove_background(image, thresh, scale_factor=.25, kernel_range=range(1, 15), border=None): 
    border = border or kernel_range[-1] 

    holes = get_holes(image, thresh) 
    small = cv.resize(holes, None, fx=scale_factor, fy=scale_factor) 
    bordered = cv.copyMakeBorder(small, border, border, border, border, cv.BORDER_CONSTANT) 

    for i in kernel_range: 
     kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (2*i+1, 2*i+1)) 
     bordered = cv.morphologyEx(bordered, cv.MORPH_CLOSE, kernel) 

    unbordered = bordered[border: -border, border: -border] 
    mask = cv.resize(unbordered, (image.shape[1], image.shape[0])) 
    fg = cv.bitwise_and(image, image, mask=mask) 
    return fg 


img = cv.imread('koAl2.jpg') 
nb_img = remove_background(img, 230) 

enter image description here

+0

versione di python? come importare cv? – grep

+0

", riga 11, in get_holes contorno, _ = cv2.findContours (im_bw_inv, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) ValoreErrore: troppi valori da decomprimere – grep

4

Mentre stavo affrontando lo stesso problema, e ha trovato una soluzione in Python (con opencv2), pensiero di solo la condivisione di questo qui. Spero che sia d'aiuto.

import numpy as np 
import cv2 

cv2.namedWindow('image', cv2.WINDOW_NORMAL) 

#Load the Image 
imgo = cv2.imread('koAl2.jpg') 
height, width = imgo.shape[:2] 

#Create a mask holder 
mask = np.zeros(imgo.shape[:2],np.uint8) 

#Grab Cut the object 
bgdModel = np.zeros((1,65),np.float64) 
fgdModel = np.zeros((1,65),np.float64) 

#Hard Coding the Rect The object must lie within this rect. 
rect = (10,10,width-30,height-30) 
cv2.grabCut(imgo,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT) 
mask = np.where((mask==2)|(mask==0),0,1).astype('uint8') 
img1 = imgo*mask[:,:,np.newaxis] 

#Get the background 
background = imgo - img1 

#Change all pixels in the background that are not black to white 
background[np.where((background > [0,0,0]).all(axis = 2))] = [255,255,255] 

#Add the background and the image 
final = background + img1 

#To be done - Smoothening the edges 

cv2.imshow('image', final) 

k = cv2.waitKey(0) 

if k==27: 
    cv2.destroyAllWindows() 
0

provare questa operazione morfologica per la dilatazione e l'erosione rimuovendo fori in C++

Mat erodeElement = getStructuringElement(MORPH_RECT, Size(4, 4)); 
morphologyEx(thresh, thresh, MORPH_CLOSE ,erodeElement); 
morphologyEx(thresh, thresh, MORPH_OPEN, erodeElement); 
morphologyEx(thresh, thresh, MORPH_CLOSE, erodeElement); 
morphologyEx(thresh, thresh, MORPH_OPEN, erodeElement); 
morphologyEx(thresh, thresh, MORPH_OPEN, erodeElement); 
Problemi correlati