remake du projet p1
Directory
Repo
Classe ProcessImg
Traitement de l’image
Dans le fichier processIng.py, la classe ProcessImg
se charge de traiter l’image à l’aide d’openCV.
-
Assignation de l’attribut
self.original
qui contient l’image originale sous forme de liste numpy. Chaque elément contient une liste contenant un $x$ un $y$ et une valeur référence de la couleur. -
Les attributs
self.height
etself.width
contiennent repectivement la largeur et la longueur totale de l’image originiale calculés à partir de la methodeshape
de l’objetself.original
-
self.processed
contient un appel de la methode__process()
qui se charge d’appliquer le traitement à l’image.
def __process(self):
img = cv2.cvtColor(self.original, cv2.COLOR_BGR2GRAY)
img = cv2.GaussianBlur(img, (3, 3), 0)
# img = cv2.Canny(img, 50, 220)
img = cv2.Canny(img, 100, 200)
# kernel = np.ones((2, 2), np.uint8)
# img = cv2.dilate(img, kernel, iterations = 1)
# img = cv2.erode(img, kernel, iterations = 1)
img = self.resize(img)
- Transformations des couleurs en dégradé de gris.
- Application d’un flou gaussien pour adoussir les bords.
- Application de l’algorithme
Canny edges
qui detecte les bords et ne garde que ces derniers. Hyrestesis set sur 100/200 - Un resize pour les images plus grandes que 640px (déterminer une valeur optimale)
def resize(self, img, width=640): if self.width > 640: img_scale = width / self.width xx = int(self.original.shape[1] * img_scale) yy = int(self.original.shape[0] * img_scale) self.height, self.width = yy, xx resized = cv2.resize(img, (xx, yy)) return resized
- Est retourné à l’attribut
self.processed
la detection de bords redimensionnée et à laquelle on ajoute un padding via la méthodepadding()
pour éviter les overflow lors de la recherche de points par la suite.def padding(self, canny): return cv2.copyMakeBorder( canny, 100, 100, 100, 100, cv2.BORDER_CONSTANT, value=0000)
Optionnel: les lignes commentées dans
__process()
permettent d’appliquer un traitement qui vise a fermer les bords incomplets de certaines images. Très efficace pour certaines images, induit cependant une perte de qualité massive dans d’autres.
Affichage
La methode self.display()
permet d’afficher l’image après process. Elle fait appel à plusieurs methodes d’openCV pour controler la fenêtre d’affichage.
classe Grid
Dans le fichier processImg.py, la class Grid
se charge de traiter une liste 2d qui sort de la classe ProcessImg
pour la mettre sous forme de liste 1d.
Elle devrait également gérer toute la logique pour permettre d’utiliser cette liste comme si l’image était sous forme d’une liste 2d. A réfléchir
self.img
contient un objet de typeProcessImg
auquel est passé l’image reçu en argument lors de l’instanciation d’un objet de typeGrid
self.canny
contient un numpy array des points composant les bords de l’image contenue dansself.img
.self.len
contient le nombre de points composantself.canny
self.height
,self.width
contiennent une vision logique du format des points contenu dansself.canny
bin_list
Cette methode retourne un bytearray
contenant les points de l’image après traitement par la methode __process()
de la classe ProcessgImg
.
Traitement liste de points
Solution 1 (depreciated)
En sortie de la méthode coords()
de la classe ProcessImg
les points sont classés ligne par ligne dans une liste. Chaque ligne est référencée par un pixel de l’axe y de notre image.
Il faut faire en sorte que le dessin soit fluide et ressemble à la façon de dessiner d’un humain et non pas à celle d’une imprimante. En gros, il nous faut Trouver une ligne qui connecte tous les points de la liste.
Shortest path problem in a graph, where:
- the graph nodes are the points in the space,
- each node is connected to its 2 nearest neighbors, and
- the shortest path passes through each of the nodes only once. That last constrain is a very important (and quite hard one to optimize).
Solution 2
Conversion image
Trouver les points d’intersection de deux cercles (angle du bras)
Liste de points (solution obsolete, openCV is the go!)
from PIL import Image
import tkinter as tk
i = Image.open("aa.png")
pixels = i.load()
width, height = i.size
coords = []
for x in range(width):
for y in range(height):
cpixel = pixels[x, y]
bw_value = int(round(sum(cpixel) / float(len(cpixel))))
if bw_value != 255:
# (x, y, (r,g,b))
coords.append((x, y, cpixel))
canvas_width = width
canvas_height = height
master = tk.Tk()
w = tk.Canvas(master, width=canvas_width, height=canvas_height)
w.pack()
for i in coords:
x1, y1 = i[0] - 1, i[1] - 1
x2, y2 = i[0] + 1, i[1] + 1
w.create_oval(x1, y1, x2, y2, fill="black")
tk.mainloop()
Variantes
monochrome
cpixel = pixels[x, y]
bw_value = int(round(sum(cpixel) / float(len(cpixel))))
# the above could probably be bw_value = sum(cpixel)/len(cpixel)
all_pixels.append(bw_value)
luminance (weighted average)
cpixel = pixels[x, y]
luma = (0.3 * cpixel[0]) + (0.59 * cpixel[1]) + (0.11 * cpixel[2])
all_pixels.append(luma)
pure 1-bit black and white
cpixel = pixels[x, y]
if round(sum(cpixel)) / float(len(cpixel)) > 127:
all_pixels.append(255)
else:
all_pixels.append(0)