[PYTHON] Tour verticale de Pise utilisant OpenCV ~

Aperçu

Récemment, j'ai appris le traitement d'image en classe et appris la technique de transformation d'un plan par transformation matricielle.

Ensuite, j'ai soudainement eu envie de rendre la tour oblique de Pise verticale, alors je vais essayer de pratiquer Python et OpenCV.

Eh bien, je peux à peine le comprendre, alors je suis un chevauchée sur les fonctions utiles d'OpenCV.

Let's Vertical!

environnement

windows10 Python 3.7.7 OpenCV 3.4.2 Pillow 7.1.2 numpy 1.18.4

la mise en oeuvre

Cliquez ici pour utiliser la tour diagonale de Pise a.jpg

Étant donné que le blanc est globalement fort, j'essaierai cette fois de détecter le contour par tonalité de couleur au lieu de bord (Sans parler de l'arrière-plan qui ne fonctionnait pas au bord)

pisa


#Détection du blanc
def detect_white_color(img):
    #Convertir en espace colorimétrique HSV
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    #Plage de valeurs HSV blanc
    hsv_min = np.array([0,0,100])
    hsv_max = np.array([180,45,255])
    mask = cv2.inRange(hsv, hsv_min, hsv_max)

    #Processus de masquage
    masked_img = cv2.bitwise_and(img, img, mask=mask)

    return mask, masked_img

a.jpga.jpg

La gauche est un masque et la droite est masked_img

Ensuite, binarisez et détectez le rectangle

pisa


imgray = cv2.cvtColor(blurred_img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,115,255,0)
im, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    rect = cv2.minAreaRect(cnt)
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    cv2.drawContours(img, [box], 0, (0,255,0), 2)

Tout d'abord, exécutez minAreaRect (contours) sur rect minAreaRect () retourne un taple avec une structure Box2D La structure de Box2D est (point supérieur gauche (x, y), taille horizontale et verticale (largeur, hauteur), angle de rotation).

Pour dessiner un rectangle, nous devons convertir ces informations en quatre coordonnées, alors exécutez boxPoints () qui peut le faire.

C'est un flux à dessiner à la fin (Référence de référence)

a.jpg

Cela semble fonctionner, mais je vais le brouiller avec un filtre gaussien au cas où pour qu'il puisse bien gérer d'autres photos!

pisa


#Flou avec le filtre gaussien
blurred_img = cv2.GaussianBlur(white_masked_img,(5,5),10)

a.jpg

Le bord s'est un peu calmé

Seul le plus grand rect est suffisant pour le ramasser

pisa


#Une fonction qui renvoie l'index du rectangle avec la plus grande surface
def detect_max_rect(img,contours):
    #Index des contours prenant la surface maximale
    max_idx = 0
    
    for i in range(len(contours)):
        if cv2.contourArea(contours[max_idx]) < cv2.contourArea(contours[i]):
            max_idx = i
    
    return max_idx

À contourArea (contours) Vous pouvez obtenir la zone de la place entourée par les coins

Utilisez ceci pour définir une fonction qui renvoie l'index des coordonnées qui maximisent la zone

Et en définissant minAreaRect (max_idx), seul le carré avec la surface maximale peut être extrait. pisa_rect.jpg

Vous vous penchez!

Let's Vertical

Je suis désolé je suis gudaguda parce que je le fais sans écrire un organigramme

Découper un rectangle en rotation

Tout d'abord, créez une fonction pour découper la zone carrée dont vous pourriez avoir besoin plus tard.

pisa



#Fonction de coupure
def crop_rect(img, rect):
    center, size, angle = rect
    center = tuple(map(int, center))  # float -> int
    size = tuple(map(int, size))  # float -> int
    h, w = img.shape[:2]  #Hauteur et largeur de l'image

    #Obtenir la hauteur et la largeur du rect
    height,width=rect[1]
    height,width=int(height),int(width)
    
    #Puisque l'angle indique l'angle formé par la ligne horizontale,+90
    if angle<0:
        angle+=90
    
    #Faire pivoter l'image à l'aide de la matrice affine
    M = cv2.getRotationMatrix2D(center, angle, 1)
    rotated = cv2.warpAffine(img, M, (w, h))

    #coupé
    cropped = cv2.getRectSubPix(rotated, (w,h), center)

    return cropped

J'ai écrit les détails dans les commentaires L'image du résultat de l'exécution est la suivante

pisa_rect_crop.jpg

C'est contre nature et intéressant

Otateru

C ’est facile car l’ angle est obtenu.

Créer une fonction pour faire pivoter l'image

pisa



#Fonction de rotation
def rotate_img(img,rect):
    #Calculez le centre de l'écran à partir de la hauteur et de la largeur
    _height = img.shape[0]                         
    _width = img.shape[1]                       
    _center = (int(_width/2), int(_height/2))
    
    _angle=rect[2]
    #Puisque l'angle indique l'angle formé par la ligne horizontale, il est de +90.
    if _angle<0:
        _angle+=90
    
    #Faire pivoter l'image à l'aide de la matrice affine
    _M = cv2.getRotationMatrix2D(_center, _angle, 1)
    _rotated_img = cv2.warpAffine(img, _M, (_width, _height))
    
    return _rotated_img

Prenez le centre de l'image et faites-la pivoter autour de l'angle de Pise.

pisa_rect_rotate.jpg

Haut parfait! !! !!







.. .. .. Je plaisante, je suis désolé Veuillez jeter la fonction précédente

En règle générale, je vais compléter la partie évidée de l'image originale et coller l'image rognée aux mêmes coordonnées.

Complément d'image

pisa


#Complément d'image
def inpaint_img(img):
    
    _mask = cv2.imread('img/pisa1.jpg')

    #Remplissez de blanc
    cv2.drawContours(_mask, [box], 0, (255,255,255), -1)
    _maskGray = cv2.cvtColor(_mask,cv2.COLOR_BGR2GRAY)
    ret,_thresh = cv2.threshold(_maskGray,254,255,0)
    
    #Correction d'image
    dst = cv2.inpaint(img, _thresh, 3, cv2.INPAINT_TELEA)
    
    cv2.imwrite('img/pisa_rect_inpaint.jpg', dst)


inpaint est l'image d'entrée et une image de masque de même taille. Est requis Les pixels avec des valeurs non nulles dans cette image de masque indiquent où réparer En d'autres termes, il peut être complété en rendant la partie que vous souhaitez réparer blanche et le reste noir.

Il existe deux types d'algorithmes, INPAINT_TELEA et INPAINT_NS, et cette fois j'ai essayé d'exécuter les deux.

a.jpg a.jpg

INPAINT_TELEA à gauche et INPAINT_NS à droite

J'ai l'impression que la partie vide de NS est un peu plus propre, j'ai donc adopté celle-ci cette fois

Otateru (prise 2)

Utiliser la bibliothèque Pillow car le collage d'images ne semble gênant qu'avec OpenCV

pisa


#Collez le pise coupé dans l'image d'arrière-plan complémentaire
def paste_pisa(rect):
    #x,Les coordonnées du centre du Pise coupé sont saisies en y
    x,y=rect[0]
    
    #Je veux l'amener en haut à gauche, donc la moitié de la largeur w et de la hauteur h x,Soustraire de y
    _w,_h=rect[1]
    #print(h,w)
    x -= _h/2
    y -= _w/2
    
    x,y=int(x),int(y)
    
    source_img = Image.open('img/pisa_rect_crop.jpg')
    canvas_img = Image.open('img/pisa_rect_inpaint.jpg')
    
    #Coller le pise taillé sur l'image peinte
    canvas_img.paste(source_img, (x,y))
    #Enregistrer l'image
    canvas_img.save('img/vertical_pisa.jpg')


Exécuter

vertical_pisa.jpg

** Pi, Pi, Pise s'est levé! !! !! ** **

Essayez de vous précipiter

1.jpg  2.jpg 3.jpg 4.jpg 10.png 5.jpg 7.jpg

à la fin

La partie complémentaire est visible et rugueuse, et elle n'est pas très verticale, mais dans l'ensemble j'ai l'impression de bien l'avoir dit.

Personnellement, j'ai été surpris de la précision de la fonction inpaint uniquement pour l'algorithme sans aucun apprentissage. De plus, le typage dynamique de python est trop pratique et c'est une phrase parfaite. .. .. Honnêtement, je ne comprends pas, mais je suis impressionné par les spécifications assouplies car il y a des endroits où j'ai procédé.

Cette fois, la zone est détectée par couleur, donc je sens que le degré de liberté augmentera s'il devient possible de le faire avec des bords la prochaine fois.

Tout le monde, ** Let'vertical! ** **

prime

** Michael vertical **

m.jpg

C'est la gravité normale

Matériel de référence

Fonction minAreaRect https://www.it-swarm.dev/ja/python/minarearect-opencv%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E8%BF%94%E3%81%95%E3%82%8C%E3%82%8B%E5%9B%9B%E8%A7%92%E5%BD%A2%E3%81%AE%E3%83%88%E3%83%AA%E3%83%9F%E3%83%B3%E3%82%B0python/824441051/

Extraction de contour https://hk29.hatenablog.jp/entry/2020/02/01/162533

Extraction du blanc https://temari.co.jp/blog/2017/11/13/opencv-4/

garniture https://teratail.com/questions/219340

fonction inpaint https://lp-tech.net/articles/kb4bO/view?page=2

Bibliothèque d'oreillers https://water2litter.net/rum/post/python_pil_paste/

Recommended Posts

Tour verticale de Pise utilisant OpenCV ~
Jugement de l'image rétroéclairée avec OpenCV
J'ai essayé d'utiliser GrabCut d'OpenCV
Exemple d'exécution de la détection d'objets blob avec OpenCV
J'ai essayé d'utiliser le filtre d'image d'OpenCV
Essayez de projeter la conversion d'image en utilisant OpenCV avec Python
Exemple d'utilisation de lambda
Implémentation de TF-IDF à l'aide de gensim
Détection de caractéristiques à l'aide d'opencv (détection de coin)
[Python] Utilisation d'OpenCV avec Python (basique)
Essayez d'utiliser OpenCV sur Windows
python: principes de base de l'utilisation de scikit-learn ①
Introduction de caffe en utilisant pyenv
Correction gamma sans utiliser OpenCV
Utiliser OpenCV avec Python @Mac
Un mémorandum d'utilisation de eigen3
Comment enregistrer une partie d'une longue vidéo en utilisant OpenCV
Alignement d'images numérisées de papier vidéo animé à l'aide d'OpenCV et de Python