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!
windows10 Python 3.7.7 OpenCV 3.4.2 Pillow 7.1.2 numpy 1.18.4
Cliquez ici pour utiliser la tour diagonale de Pise
É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
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)
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)
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.
Vous vous penchez!
Let's Vertical
Je suis désolé je suis gudaguda parce que je le fais sans écrire un organigramme
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
C'est contre nature et intéressant
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.
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.
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.
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
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
** Pi, Pi, Pise s'est levé! !! !! ** **
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! ** **
C'est la gravité normale
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