Projet Python : Redressement d’images de tableau P. Vanier, T. Kaced Projet Python : Redressement d’images de tableau Dernière modification : 28 septembre 2015 [email protected] 1 Consignes — Date limite inscription groupes : 5 octobre — Date limite rendu sur gitlab : 29 novembre — Date de la soutenance : Semaine du 30 novembre. Le projet est à faire par groupe d’au plus 2 personnes, vous devez inscrire le groupe sur la page eprel avant le 5 octobre. Vous devez vous servir de git pour le rendu, l’interface gitlab est http://git-etudiants.lacl.fret des slides d’initiation à git sont disponibles sur la page eprel du cours de systèmes en L2. Vous devez écrire un rapport (un simple fichier texte nommé rapport) que vous mettrez à la racine de votre projet. Seuls les projets rendus sur http://git-etudiants.lacl.frseront acceptés, vous devez faire des commit régulièrement (un seul commit à la dernière minute entrainera une perte de plusieurs points sur la note finale). 2 Le sujet Le but de ce projet est d’écrire un package/module permettant à partir d’une photo de tableau d’obtenir une image lisible et redressée, voir la figure 1. Le projet peut être décomposé en plusieurs étapes intermédiaires : 1. Détection des bords du tableau 2. Découpage et redressement de l’image 3. Améliorations de l’image Nous vous donnons ci-dessous une méthode pour faire chacune de ces étapes, celle-ci est tirée de l’article Whiteboard Scanning and Image Enhancement de Zhengyou Zhang et Li-wei He, que vous pouvez trouver dans le répertoire du projet sur éprel. Vous n’êtes pas obligés de suivre cette méthode (vous pouvez l’améliorer si vous le souhaitez). Vous pouvez vous servir de packages/modules python que vous voulez, y compris opencv (seule les versions 3.0 et postérieures sont compatibles python 3) ou de scikit-image. 3 3.1 Détecter les bords Détection de contours La première étape pour détecter les contours est de prendre l’image convertie en niveaux de gris. On utilise ensuite un filtre de Sobel pour calculer deux gradients pour chaque pixel : M1 Python – Cours : P. Vanier 1/5 Projet Python : Redressement d’images de tableau (a) Avant P. Vanier, T. Kaced (b) Après Figure 1: Exemple d’image de tableau. −1 0 1 −1 −2 −1 0 0 et le filtre en y : Gy = −2 0 2 Le filtre en x : Gx = 0 −1 0 1 1 2 1 Ces deux filtres sont les filtres horizontaux et verticaux par défaut pour le filtre de Sobel d’opencv2 étant donné les paramètres — dx = 1, dy = 0, ksize = 3 et — dx = 0, dy = 1, ksize = 3 . Il suffit alors de calculer le gradient total G = |Gx | + Gy pour chaque pixel. On peut alors définir un seuil TG tel que tout pixel où G ≥ TG sera considéré comme faisant partie d’un contour. On pourra prendre TG = 40. On aurait également pu détecter les contours avec un filtre de Canny par exemple. 3.2 Détection de lignes On a maintenant une image temporaire contenant uniquement du blanc et du noir : une image binaire donc, où le blanc représente un contour et le noir le fond. On veut cependant uniquement conserver les contours correspondant à notre tableau : on ne veut conserver que les contours qui forment des segments. On va utiliser pour cela une transformation de Hough (également disponible dans opencv). Cette transformée permet d’obtenir une liste de droites. Il faut ensuite calculer pour chaque droite son orientation, ce qui peut se faire en prenant atan2(G_y, G_x) pour n’importe quel point de cette droite où l’image binaire contenait du blanc. Vous pouvez également réimplémenter la transformée de Hough 3.3 Détection de quadrilatère Une fois que vous avez détecté les lignes, il faut déterminer lesquelles seront considérées pour former le contour du tableau. Pour cela, on prendra des quadruples de droites qui vérifient les conditions suivantes : M1 Python – Cours : P. Vanier 2/5 Projet Python : Redressement d’images de tableau P. Vanier, T. Kaced — Les lignes opposées doivent avoir des orientations opposées : 180 ± 30. — Les lignes opposées doivent être relativement loin les unes des autres (par exemple la différence entre les ρ est plus grande que 1/5 de la largeur/hauteur de l’image). — L’angle entre deux lignes consécutives doit s’approcher de 90 ± 30 — Le quadrilatère ainsi formé doit être relativement grand (plus grand que (L + H)/4 par exemple). Les lignes renvoyées par la transformée de Hough ne disent cependant pas où se trouvaient les segments correspondant, et si l’on peut, même en vérifiant toutes les conditions précédentes se retrouver dans la situation suivante : Pour éviter cette situation, il faut parcourir ces droites sur l’image en binaire et regarder si le segment initial correspond bien à un bord du quadrilatère formé par les droites. On conservera le meilleur quadrilatère. On peut utiliser à ce stade diverses techniques pour raffiner le quadrilatère (c’est mieux, mais ce n’est pas obligatoire), par exemple un line-fitting pour chaque bord. 4 Redressement de l’image Il faut déterminer la taille du rectangle dans lequel on mettra notre sous-image de tableau. Supposons que les coordonnées des coins détectés du tableau soient m1 , m2 , m3 , m4 (où la troisième coordonnée est mise à 1), la figure ci-dessous est une vue schématique de la manière dont la photo a été prise : M1 Python – Cours : P. Vanier 3/5 Projet Python : Redressement d’images de tableau P. Vanier, T. Kaced On calcule le rapport de cadre (aspect ratio) du rectangle : s t n t A−1 A−1 n 2 2 r = w/h = t n t A−1 n 3 3 — k2 = (m1 ×m4 )·m3 (m2 ×m4 )·m3 (m1 ×m4 )·m2 (m3 ×m4 )·m2 — k3 = — n2 = k2 m2 − m1 — n3 =k3 m3 − m1 f 0 u0 — A = 0 sf v0 où (u0 , v0 ) est le centre de l’image. 0 0 1 — f 2 = − n 1n (n21 n31 −(n21 n33 +n23 n31 )u0 +n23 n33 u02 +n22 n32 −(n22 n33 +n23 n32 )v0 +n23 n33 v02 ) 23 33 où nij est la j-ème coordonnée de ni . Une fois r calculé, on peut obtenir des dimensions pour notre nouvelle image : Pour cela on définit W = max(W1 , W2 ) (où W1 et W2 sont les longueurs des bords horizontaux) et H = max(H1 , H2 ) (les longueurs des bords verticaux). On calcule alors un rapport temporaire r = W /H et : — Si r ≥ r alors W = W et H = W /r — Sinon H = H et W = rH. 5 Correction de l’image Il faut ensuite corriger l’image pour rendre l’arrière plan blanc uniforme se débarasser en particulier des reflets et autres bruits non désirés. La technique est expliquée dans l’article sur Eprel. 6 Améliorations Vous pouvez améliorer le projet comme vous le souhaitez : interface graphique, reconstruction d’image de tableau à partir de plusieurs images partielles... A Installer opencv Pour pouvoir utiliser opencv avec python 3, il faut que vous installiez la dernière version d’opencv ainsi que numpy. Installer numpy est très simple : pip install numpy. — Sous archlinux yaourt opencv-git M1 Python – Cours : P. Vanier 4/5 Projet Python : Redressement d’images de tableau P. Vanier, T. Kaced — Sous gentoo emerge opencv-3.0.0 — Sous ubuntu/debian/mint des instructions sont disponibles : http://docs.opencv.org/ doc/tutorials/introduction/linux_install/linux_install.html N’oubliez pas d’installer les paquets libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libjpeg8-dev libtiff4-dev libjasper-dev libpng12-dev build-essential cmake git pkg-config B Installer scikit-image Il suffit d’utiliser pip. M1 Python – Cours : P. Vanier 5/5