diff --git a/.gitignore b/.gitignore index 628de45..9a3ebba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .vscode/ imageEngine/images/ imageEngine/test/ -imageEngine/__pycache__/ \ No newline at end of file +imageEngine/__pycache__/ +imageEngine/filters/__pycache__/ +imageEngine/test.py \ No newline at end of file diff --git a/imageEngine/filters/canny.py b/imageEngine/filters/canny.py index f1469fc..86e239c 100644 --- a/imageEngine/filters/canny.py +++ b/imageEngine/filters/canny.py @@ -1,39 +1,32 @@ -from usefull_func import * -from math import sqrt, atan2 +from copy import deepcopy +from filters.usefull_func import * +from math import sqrt, atan2, pi -#En_cours... -def filtre_canny(img): - def norme_gradient(pixel1, pixel2): - color_x = pixel1[0] - color_y = pixel2[0] - - norm = round(sqrt(color_x**2 + color_y**2)) - norm = min(norm, 255) +def filtreCanny(img, Th): + Tl = Th / 2 - grad = atan2(color_y, color_x) - return norm, grad + filtred_image = filtre_gaussien(img) - def liste_normGrad(im1, im2): - liste = [] - for j in range(len(im1)): - ligne = [] - for i in range(len(im1[0])): - normGrad = norme_gradient(im1[j][i], im2[j][i]) - ligne.append(normGrad) - liste.append(ligne) - return liste + norme_gradient, angle_normale_gradient = calculGradient(filtred_image) - if not is_greyscale(img): - img = greyscale(img) - - mat_x = [[-1,0,1]] - mat_y = [[1],[0],[-1]] + non_maxima = dltNoMaxima(norme_gradient, angle_normale_gradient) - #lissage/suppression des bri - img_no_bruit = convolution_gauss(img) - Jx = convolution(img, mat_x) - Jy = convolution(img, mat_y) - normGrad = liste_normGrad(Jx, Jy) - #Suppresion des non-maximum + contours = seuillageHysteresis(non_maxima, angle_normale_gradient, Th, Tl) + return contours + +""" +def filtreCannySemiAuto(img, centile): + filtred_image = filtre_gaussien(img) + + norme_gradient, angle_normale_gradient = calculGradient(filtred_image) + + non_maxima = dltNoMaxima(norme_gradient, angle_normale_gradient) + + Th = calculTh(norme_gradient, centile) + Tl = Th / 2 + contours = seuillageHysteresis(non_maxima, angle_normale_gradient, Th, Tl) + + return contours +""" diff --git a/imageEngine/filters/sobel.py b/imageEngine/filters/sobel.py index 677ec51..17cebb7 100644 --- a/imageEngine/filters/sobel.py +++ b/imageEngine/filters/sobel.py @@ -1,5 +1,4 @@ -from usefull_func import * - +from filters.usefull_func import * def filtre_sobel(img): diff --git a/imageEngine/filters/usefull_func.py b/imageEngine/filters/usefull_func.py index af173a5..eb5d9d8 100644 --- a/imageEngine/filters/usefull_func.py +++ b/imageEngine/filters/usefull_func.py @@ -1,4 +1,5 @@ -from math import sqrt +from copy import deepcopy +from math import atan2, sqrt, pi def greyscale(mat_img): gray_img = [] @@ -10,26 +11,29 @@ def greyscale(mat_img): gray_img.append(lig) return gray_img + def appliquer_convolution(img, mat, i, j): somme = 0 - for y in range(len(mat)): - for x in range(len(mat[0])): - pixel_i = i - (len(mat[0]) // 2) + x - pixel_j = j - (len(mat) // 2) + y - pix = pixel(img, pixel_i, pixel_j) - somme += pix[0]*mat[y][x] + for x in range(len(mat)): + for y in range(len(mat[0])): + coord_i = i - (len(mat) // 2) + x + corrd_j = j - (len(mat[0]) // 2) + y + pix = pixel(img, coord_i, corrd_j) + somme += pix[0]*mat[x][y] return min(max(somme,0), 255) + def convolution(mat_img, mat): return_img = [] - for j in range(len(mat_img)): + for i in range(len(mat_img)): ligne = [] - for i in range(len(mat_img[0])): + for j in range(len(mat_img[0])): val = appliquer_convolution(mat_img, mat, i, j) ligne.append((val,)*3) return_img.append(ligne) return return_img + def is_greyscale(img): _greyscale = True for ligne in img: @@ -41,6 +45,7 @@ def is_greyscale(img): break return _greyscale + def invert(img): result_image = [] for ligne in img: @@ -50,25 +55,28 @@ def invert(img): result_image.append(result_ligne) return result_image + def pixel(img, i, j, default=(0,0,0)): #i la colone et j la ligne - if 0 <= i < len(img[0]) and 0 <= j < len(img): - return img[j][i] + if 0 <= i < len(img) and 0 <= j < len(img[0]): + return img[i][j] else: return default + def reduction_bruit(img, mat, i, j): somme = 0 - for y in range(len(mat)): - for x in range(len(mat[0])): - pixel_i = i - (len(mat[0]) // 2) + x - pixel_j = j - (len(mat) // 2) + y + for x in range(len(mat)): + for y in range(len(mat[0])): + pixel_i = i - (len(mat) // 2) + x + pixel_j = j - (len(mat[0]) // 2) + y pix = pixel(img, pixel_i, pixel_j) - somme += pix[0]*mat[y][x] + somme += pix[0]*mat[x][y] normalise = round(somme) return normalise -def convolution_gauss(mat_img): + +def filtre_gaussien(mat_img): mat_gauss = [ [2/159, 4/159, 5/159, 4/159,2/159], [4/159, 9/159,12/159, 9/159,4/159], @@ -78,28 +86,208 @@ def convolution_gauss(mat_img): ] return_img = [] - for j in range(len(mat_img)): + for i in range(len(mat_img)): ligne = [] - for i in range(len(mat_img[0])): + for j in range(len(mat_img[0])): val = reduction_bruit(mat_img, mat_gauss, i, j) ligne.append((val,)*3) return_img.append(ligne) return return_img + def calcul_norme(pixel1, pixel2): valeur = pixel1[0]**2 + pixel2[0]**2 norm = round(sqrt(valeur)) norm = int(min(norm, 255)) return norm + def application_norme(im_x, im_y): result_image = [] - for j in range(len(im_x)): + for i in range(len(im_x)): ligne = [] - for i in range(len(im_x[0])): - pixel1 = im_x[j][i] - pixel2 = im_y[j][i] + for j in range(len(im_x[0])): + pixel1 = im_x[i][j] + pixel2 = im_y[i][j] norme = calcul_norme(pixel1, pixel2) ligne.append((norme,)*3) result_image.append(ligne) - return result_image \ No newline at end of file + return result_image + + +def calculGradient(filtred_image): + mask_x = [[1, 0, -1]] + mask_y = [[1],[0],[-1]] + + mask_gradient_x = convolution(filtred_image, mask_x) + mask_gradient_y = convolution(filtred_image, mask_y) + + norme_gradient = copyNullMatrix(filtred_image) + angle_normal_gradient = copyNullMatrix(filtred_image) + + for i in range(len(filtred_image)): + for j in range(len(filtred_image[0])): + Jx = mask_gradient_x[i][j][0] + Jy = mask_gradient_y[i][j][0] + norme_gradient[i][j] = sqrt(Jx**2 + Jy**2) + angle_temp = atan2(Jy,Jx) + angle_normal_gradient[i][j] = transform_angle(angle_temp) + + return norme_gradient, angle_normal_gradient + + +def copyNullMatrix(mat): + nullMat = deepcopy(mat) + for i in range(len(nullMat)): + for j in range(len(nullMat[0])): + nullMat[i][j] = 0 + return nullMat + + +def transform_angle(radient): + angle = radient * 180 / pi + if angle < 0: + angle += 180 + + #On veut que la valeur de l'angle soit 0, 45, 90 ou 135° + seuil_min_45 = 45/2 + seuil_min_90 = (90+45)/2 + seuil_min_135 = (135+90)/2 + seuil_max_135 = (180+135)/2 + + if seuil_min_45 <= angle < seuil_min_90: + angle = 45 + elif seuil_min_90 <= angle < seuil_min_135: + angle = 90 + elif seuil_min_135 <= angle < seuil_max_135: + angle = 135 + else: + angle = 0 + + return angle + + +def dltNoMaxima(norme_gradient, angle_normal_gradient): + non_maxima = copyNullMatrix(norme_gradient) + + for i in range(len(non_maxima)): + for j in range(len(non_maxima[0])): + angle = angle_normal_gradient[i][j] + voisin1, voisin2 = norm_voisin(norme_gradient, angle, i, j) + if norme_gradient[i][j] < voisin1 or norme_gradient[i][j] < voisin2: + non_maxima[i][j] = 0 + else: + non_maxima[i][j] = norme_gradient[i][j] + return non_maxima + + +def get_norm(norm_list, i, j): + norm = 0 + if 0 <= i < len(norm_list) and 0 <= j < len(norm_list[0]): + norm = norm_list[i][j] + return norm + + +def norm_voisin(norm_list, angle, i, j): + voisin1 = None + voisin2 = None + + if angle == 0: + voisin1 = get_norm(norm_list,i,j-1) + voisin2 = get_norm(norm_list,i,j+1) + elif angle == 45: + voisin2 = get_norm(norm_list,i-1,j+1) + voisin1 = get_norm(norm_list,i+1,j-1) + elif angle == 90: + voisin1 = get_norm(norm_list,i-1,j) + voisin2 = get_norm(norm_list,i+1,j) + elif angle == 135: + voisin2 = get_norm(norm_list,i-1,j-1) + voisin1 = get_norm(norm_list,i+1,j+1) + + return voisin1, voisin2 + + +def seuillageHysteresis(non_maxima, angle_normale_gradient, Th, Tl): + contours = deepcopy(non_maxima) + + for i in range(len(angle_normale_gradient)): + for j in range(len(angle_normale_gradient[0])): + if non_maxima[i][j] > Th: + contours[i][j] = (255,)*3 + elif non_maxima[i][j] < Tl: + contours[i][j] = (0,)*3 + + + for i in range(len(angle_normale_gradient)): + for j in range(len(angle_normale_gradient[0])): + if Tl <= non_maxima[i][j] <= Th: + angle = angle_normale_gradient[i][j] + 90 + if angle >= 180: + angle -= 180 + + voisin1, voisin2 = norm_voisin(non_maxima, angle, i, j) + if voisin1 > Th and voisin2 > Th: + contours[i][j] = (255,)*3 + else: + contours[i][j] = (0,)*3 + return contours + + +""" +def calculTh(norme_gradient, centile): + histogramme, pas = calculHistogram(norme_gradient) + fonctionRepartition = calculFonctionRepartition(histogramme) + + nbrPixels = len(norme_gradient)*len(norme_gradient[0]) + pivot = nbrPixels * centile + + Th_index = 0 + for i in range(len(fonctionRepartition)): + if (pivot - fonctionRepartition[0][Th_index]) > (pivot - fonctionRepartition[0][i]) and (pivot - fonctionRepartition[i] > 0): + Th_index = i + + Th = pas * (Th_index - 1) + return Th + +def calculHistogram(norme_gradient): + norme_max = Maxi(norme_gradient) + norme_min = Minim(norme_gradient) + ecart = norme_max - norme_min + + nb_pas = 1000 + pas = ecart / (nb_pas - 1) + + histogram = [[0]*nb_pas] + + for i in range(len(norme_gradient)): + for j in range(len(norme_gradient[0])): + valeur_pixel = norme_gradient[i][j] + position = floor((valeur_pixel - norme_min) / pas) + histogram[0][position] += 1 + + return histogram, pas + +def calculFonctionRepartition(histogram): + fonctionRepartition = deepcopy(histogram) + for i in range(1, len(fonctionRepartition[0])): + fonctionRepartition[0][i] = fonctionRepartition[0][i-1] + histogram[0][i-1] + + return fonctionRepartition + +def Maxi(mat): + mx = 0 + for i in range(len(mat)): + for j in range(len(mat[0])): + if mat[i][j] > mx: + mx = mat[i][j] + return mx + +def Minim(mat): + mn = 1000 + for i in range(len(mat)): + for j in range(len(mat[0])): + if mat[i][j] < mn: + mn = mat[i][j] + return mn +"""