[PYTHON] Vertikaler Turm von Pisa mit OpenCV ~

Überblick

Kürzlich habe ich im Unterricht die Bildverarbeitung gelernt und die Technik der Transformation einer Ebene durch Matrixtransformation gelernt.

Dann bekam ich plötzlich den Drang, Pisas schrägen Turm vertikal zu machen, also werde ich versuchen, Python und OpenCV zu üben.

Nun, ich kann es kaum verstehen, also bin ich ein Huckepack-Fahrer mit den nützlichen Funktionen von OpenCV.

Lassen Sie uns vertikal!

Umgebung

windows10 Python 3.7.7 OpenCV 3.4.2 Pillow 7.1.2 numpy 1.18.4

Implementierung

Klicken Sie hier, um den diagonalen Turm von Pisa zu verwenden a.jpg

Da Weiß insgesamt stark ist, werde ich diesmal versuchen, den Umriss anhand des Farbtons anstelle der Kante zu erkennen (Ganz zu schweigen von dem Hintergrund, der am Rand nicht funktioniert hat)

pisa


#Weißerkennung
def detect_white_color(img):
    #In HSV-Farbraum konvertieren
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    #Weißer HSV-Wertebereich
    hsv_min = np.array([0,0,100])
    hsv_max = np.array([180,45,255])
    mask = cv2.inRange(hsv, hsv_min, hsv_max)

    #Maskierungsprozess
    masked_img = cv2.bitwise_and(img, img, mask=mask)

    return mask, masked_img

a.jpga.jpg

Die linke ist mask und die rechte ist masked_img

Als nächstes binarisieren und erkennen Sie das Rechteck

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)

Führen Sie zuerst minAreaRect (Konturen) auf rect aus minAreaRect () gibt einen Taple mit einer Box2D-Struktur zurück Die Struktur von Box2D ist (oberer linker Punkt (x, y), horizontale und vertikale Größe (Breite, Höhe), Drehwinkel).

Um ein Rechteck zu zeichnen, müssen wir diese Informationen in vier Koordinaten konvertieren. Führen Sie also boxPoints () aus, die dies können.

Es ist ein Fluss, der am Ende gezeichnet werden muss (Referenz Referenz)

a.jpg

Es scheint zu funktionieren, aber ich werde es mit einem Gaußschen Filter verwischen, nur für den Fall, dass es andere Fotos gut verarbeiten kann!

pisa


#Mit Gauß-Filter verwischen
blurred_img = cv2.GaussianBlur(white_masked_img,(5,5),10)

a.jpg

Die Kante hat sich ziemlich beruhigt

Nur das größte Rechteck reicht aus, um es aufzunehmen

pisa


#Eine Funktion, die den Index des Rechtecks mit der größten Fläche zurückgibt
def detect_max_rect(img,contours):
    #Index der Konturen, die die maximale Fläche einnehmen
    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

Unter [contourArea (contours)](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html#contour- Sie können den Bereich des Platzes von den Ecken umgeben bekommen

Verwenden Sie diese Option, um eine Funktion zu definieren, die den Index der Koordinaten zurückgibt, die den Bereich maximieren

Durch Festlegen von minAreaRect (max_idx) kann nur das Quadrat mit der maximalen Fläche extrahiert werden. pisa_rect.jpg

Du lehnst dich!

Let's Vertical

Es tut mir leid, dass ich es mache, ohne ein Flussdiagramm zu schreiben

Trimmen eines rotierenden Rechtecks

Erstellen Sie zunächst eine Funktion zum Trimmen des quadratischen Bereichs, den Sie später möglicherweise benötigen.

pisa



#Ausschaltfunktion
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]  #Bildhöhe und -breite

    #Holen Sie sich Höhe und Breite von Rect
    height,width=rect[1]
    height,width=int(height),int(width)
    
    #Da der Winkel den durch die horizontale Linie gebildeten Winkel angibt,+90
    if angle<0:
        angle+=90
    
    #Drehen Sie das Bild mit der affinen Matrix
    M = cv2.getRotationMatrix2D(center, angle, 1)
    rotated = cv2.warpAffine(img, M, (w, h))

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

    return cropped

Ich habe die Details in den Kommentaren geschrieben Das Bild des Ausführungsergebnisses ist wie folgt

pisa_rect_crop.jpg

Es ist unnatürlich und interessant

Otateru

Es ist einfach, weil der Winkel erhalten wird.

Erstellen Sie eine Funktion zum Drehen des Bildes

pisa



#Funktion zum Drehen
def rotate_img(img,rect):
    #Berechnen Sie die Bildschirmmitte aus Höhe und Breite
    _height = img.shape[0]                         
    _width = img.shape[1]                       
    _center = (int(_width/2), int(_height/2))
    
    _angle=rect[2]
    #Da der Winkel den durch die horizontale Linie gebildeten Winkel angibt, beträgt er +90.
    if _angle<0:
        _angle+=90
    
    #Drehen Sie das Bild mit der affinen Matrix
    _M = cv2.getRotationMatrix2D(_center, _angle, 1)
    _rotated_img = cv2.warpAffine(img, _M, (_width, _height))
    
    return _rotated_img

Nehmen Sie die Bildmitte und drehen Sie sie um den Winkel von Pisa.

pisa_rect_rotate.jpg

Hoch perfekt! !! !!







.. .. .. Ich mache Witze, es tut mir leid Bitte werfen Sie die vorherige Funktion weg

Als Richtlinie werde ich den ausgehöhlten Teil aus dem Originalbild ergänzen und das zugeschnittene Bild an denselben Koordinaten einfügen.

Bildkomplement

pisa


#Bildkomplement
def inpaint_img(img):
    
    _mask = cv2.imread('img/pisa1.jpg')

    #Mit Weiß füllen
    cv2.drawContours(_mask, [box], 0, (255,255,255), -1)
    _maskGray = cv2.cvtColor(_mask,cv2.COLOR_BGR2GRAY)
    ret,_thresh = cv2.threshold(_maskGray,254,255,0)
    
    #Bildkorrektur
    dst = cv2.inpaint(img, _thresh, 3, cv2.INPAINT_TELEA)
    
    cv2.imwrite('img/pisa_rect_inpaint.jpg', dst)


inpaint ist das Eingabebild und ein Maskenbild derselben Größe. Wird benötigt Pixel mit Werten ungleich Null in diesem Maskenbild geben an, wo repariert werden muss Mit anderen Worten, es kann ergänzt werden, indem das zu reparierende Teil weiß und der Rest schwarz gemacht wird.

Es gibt zwei Arten von Algorithmen, INPAINT_TELEA und INPAINT_NS, und dieses Mal habe ich versucht, beide auszuführen.

a.jpg a.jpg

Links INPAINT_TELEA und rechts INPAINT_NS

Ich habe das Gefühl, dass der leere Teil von NS etwas sauberer ist, deshalb habe ich diesen dieses Mal übernommen

Otateru (Nimm 2)

Verwenden der Pillow-Bibliothek, da das Einfügen von Bildern nur mit OpenCV problematisch zu sein scheint

pisa


#Fügen Sie die zugeschnittene Pisa in das ergänzende Hintergrundbild ein
def paste_pisa(rect):
    #x,Die Mittelkoordinaten des getrimmten Pisa werden in y eingegeben
    x,y=rect[0]
    
    #Ich möchte es nach links oben bringen, also die Hälfte der Breite w und Höhe h x,Von y subtrahieren
    _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')
    
    #Fügen Sie zugeschnittenes Pisa auf das bemalte Bild ein
    canvas_img.paste(source_img, (x,y))
    #Bild speichern
    canvas_img.save('img/vertical_pisa.jpg')


Ausführen

vertical_pisa.jpg

** Pi, Pi, Pisa stand auf! !! !! ** ** **

Versuchen Sie es schnell zu machen

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

schließlich

Der komplementäre Teil ist sichtbar und rau und nicht sehr vertikal, aber insgesamt habe ich das Gefühl, dass ich es gut gesagt habe.

Persönlich war ich überrascht über die Genauigkeit der Inpaint-Funktion nur für den Algorithmus ohne jegliches Lernen. Auch die dynamische Eingabe von Python ist zu bequem und eine perfekte Phrase. .. .. Ehrlich gesagt verstehe ich nicht, aber ich bin beeindruckt von den entspannten Spezifikationen, weil es Orte gibt, an denen ich vorgegangen bin

Dieses Mal wird der Bereich anhand der Farbe erkannt. Wenn Sie dies also beim nächsten Mal mit der Kante tun können, wird der Freiheitsgrad meiner Meinung nach zunehmen.

Jeder, ** Let'vertical! ** ** **

Bonus

** Vertikaler Michael **

m.jpg

Das ist normale Schwerkraft

Referenzmaterial

minAreaRect-Funktion 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/

Konturextraktion https://hk29.hatenablog.jp/entry/2020/02/01/162533

Weiße Extraktion https://temari.co.jp/blog/2017/11/13/opencv-4/

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

Inpaint-Funktion https://lp-tech.net/articles/kb4bO/view?page=2

Kissenbibliothek https://water2litter.net/rum/post/python_pil_paste/

Recommended Posts

Vertikaler Turm von Pisa mit OpenCV ~
Beurteilung des hintergrundbeleuchteten Bildes mit OpenCV
Ich habe versucht, GrabCut von OpenCV zu verwenden
Ausführungsbeispiel für die Blob-Erkennung mit OpenCV
Ich habe versucht, den Bildfilter von OpenCV zu verwenden
Versuchen Sie, die Bildkonvertierung mit OpenCV mit Python zu projizieren
Beispiel für die Verwendung von Lambda
Implementierung von TF-IDF mit Gensim
Feature-Erkennung mit opencv (Eckenerkennung)
[Python] Verwenden von OpenCV mit Python (Basic)
Versuchen Sie es mit OpenCV unter Windows
Python: Grundlagen der Verwendung von Scikit-Learn ①
Einführung von Kaffee mit Pyenv
Gammakorrektur ohne OpenCV
Verwenden von OpenCV mit Python @Mac
Ein Memorandum zur Verwendung von eigen3
So speichern Sie einen Teil eines langen Videos mit OpenCV
Ausrichten gescannter Bilder von animiertem Videopapier mit OpenCV und Python