web-dev-qa-db-fra.com

Supprimer le bruit de l'image seuil opencv python

J'essaie d'obtenir les coins de la boîte en image. Voici des exemples d'images, leurs résultats de seuil et à droite après la flèche sont les résultats dont j'ai besoin. Vous avez peut-être déjà vu ces images sur Slack parce que j'utilise ces images pour mes exemples de questions sur Slack.

enter image description here

Voici le code qui me permet d'atteindre jusqu'à l'image du milieu.

import cv2
import numpy as np

img_file = 'C:/Users/box.jpg'
img = cv2.imread(img_file, cv2.IMREAD_COLOR)
img = cv2.blur(img, (5, 5))

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)

thresh0 = cv2.adaptiveThreshold(s, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
thresh1 = cv2.adaptiveThreshold(v, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
thresh2 = cv2.adaptiveThreshold(v, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
thresh = cv2.bitwise_or(thresh0, thresh1)

cv2.imshow('Image-thresh0', thresh0)
cv2.waitKey(0)
cv2.imshow('Image-thresh1', thresh1)
cv2.waitKey(0)
cv2.imshow('Image-thresh2', thresh2)
cv2.waitKey(0)

Y a-t-il une méthode en opencv qui peut le faire pour moi? J'ai essayé la dilatation cv2.dilate() et l'érosion cv2.erode() mais cela ne fonctionne pas dans mes cas.Ou sinon, quelles pourraient être d'autres façons de le faire? Merci

Version canne de l'image ... A gauche avec seuil bas et à droite avec seuil haut

enter image description here

13
muazfaiz

Vous pouvez lisser l'image dans une certaine mesure en appliquant des opérations morphologiques de fermeture et d'ouverture alternatives avec un élément structurant agrandi.Voici les versions originales et lissées.

imsmoothim2smooth2

Prenez ensuite le gradient morphologique de l'image.

gradgrad2

Appliquez ensuite le seuil Otsu à chacun des canaux et fusionnez ces canaux.

mergedmerged2

Si vos tailles d'image sont différentes (plus grandes), vous souhaiterez peut-être modifier certains des paramètres du code ou redimensionner grossièrement les images aux tailles utilisées ici. Le code est dans c++ mais il ne sera pas difficile de le porter sur python.

/* load color image */
Mat im = imread(INPUT_FOLDER_PATH + string("2.jpg"));
/* 
smooth the image with alternative closing and opening
with an enlarging kernel
*/
Mat morph = im.clone();
for (int r = 1; r < 4; r++)
{
    Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(2*r+1, 2*r+1));
    morphologyEx(morph, morph, CV_MOP_CLOSE, kernel);
    morphologyEx(morph, morph, CV_MOP_OPEN, kernel);
}
/* take morphological gradient */
Mat mgrad;
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
morphologyEx(morph, mgrad, CV_MOP_GRADIENT, kernel);

Mat ch[3], merged;
/* split the gradient image into channels */
split(mgrad, ch);
/* apply Otsu threshold to each channel */
threshold(ch[0], ch[0], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
threshold(ch[1], ch[1], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
threshold(ch[2], ch[2], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
/* merge the channels */
merge(ch, 3, merged);
10
dhanushka

Ci-dessous, une implémentation de python de l'approche de @ dhanushka

import cv2
import numpy as np

# load color image
im = cv2.imread('input.jpg')

# smooth the image with alternative closing and opening
# with an enlarging kernel
morph = im.copy()

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))

# take morphological gradient
gradient_image = cv2.morphologyEx(morph, cv2.MORPH_GRADIENT, kernel)

# split the gradient image into channels
image_channels = np.split(np.asarray(gradient_image), 3, axis=2)

channel_height, channel_width, _ = image_channels[0].shape

# apply Otsu threshold to each channel
for i in range(0, 3):
    _, image_channels[i] = cv2.threshold(~image_channels[i], 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY)
    image_channels[i] = np.reshape(image_channels[i], newshape=(channel_height, channel_width, 1))

# merge the channels
image_channels = np.concatenate((image_channels[0], image_channels[1], image_channels[2]), axis=2)

# save the denoised image
cv2.imwrite('output.jpg', image_channels)

Le code ci-dessus ne donne pas de bons résultats si l'image que vous traitez est une facture (ou contient une grande quantité de texte sur un fond blanc). Pour obtenir de bons résultats sur ces images, supprimez

gradient_image = cv2.morphologyEx(morph, cv2.MORPH_GRADIENT, kernel)

et passez morph obj à la fonction split et supprimez le ~ symbole à l'intérieur pour la boucle

10
Shreesha N

Je ne sais pas à quel point cette solution sera robuste, mais l'idée est assez simple. Les bords de la boîte devraient être plus prononcés que toutes les autres hautes fréquences sur ces images. Ainsi, l'utilisation d'un prétraitement de base devrait permettre de les mettre en valeur.

J'ai utilisé votre code pour créer un prototype mais la recherche de contour n'a pas besoin d'être le bon chemin. Désolé également pour le masquage flou itératif - n'a pas eu le temps d'ajuster les paramètres.

result

import cv2
import numpy as np

def unsharp_mask(img, blur_size = (9,9), imgWeight = 1.5, gaussianWeight = -0.5):
    gaussian = cv2.GaussianBlur(img, (5,5), 0)
    return cv2.addWeighted(img, imgWeight, gaussian, gaussianWeight, 0)

img_file = 'box.png'
img = cv2.imread(img_file, cv2.IMREAD_COLOR)
img = cv2.blur(img, (5, 5))
img = unsharp_mask(img)
img = unsharp_mask(img)
img = unsharp_mask(img)

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)

thresh = cv2.adaptiveThreshold(s, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
_, contours, heirarchy = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(contours, key = cv2.contourArea, reverse = True)
#for cnt in cnts:
canvas_for_contours = thresh.copy()
cv2.drawContours(thresh, cnts[:-1], 0, (0,255,0), 3)
cv2.drawContours(canvas_for_contours, contours, 0, (0,255,0), 3)
cv2.imshow('Result', canvas_for_contours - thresh)
cv2.imwrite("result.jpg", canvas_for_contours - thresh)
cv2.waitKey(0)
3
m3h0w