Ich habe mit OpenCV ein Tool zum Zuschneiden von Bildern erstellt. Schneiden Sie das Objekt aus, projizieren Sie es, formen Sie es und speichern Sie jedes Objekt.
Es wird angenommen, dass das Objekt ein Film mit dem folgenden Bild ist. Auch wenn dies nicht der Fall ist, kann es meiner Meinung nach beim Extrahieren eines Rechtecks verwendet werden.
<img width="200", alt="sample.jpg ", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779817/f532ad11-9c6d-e7df-844b-a30e6a2851ea.jpeg "> <img width="100", alt="sample2.png ", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779817/528427a2-9619-e2d1-b189-8a513cf87c64.jpeg ">
Da ich während der Erstellung auf die Projektionskonvertierung gestoßen bin, werden Inhalt und Lösung am Ende beschrieben.
Mac OS python 3.8.5
opencv-python 4.4.0.44 numpy 1.19.2 tqdm 4.50.2
python
pip install opencv-python
pip install tqdm
<img width="350", alt="射影変換後.jpeg ", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779817/5b69d421-8b17-d09c-b6d4-e7843473ccb2.jpeg ">
Ich importiere tqdm, um den Umgebungsfortschrittsbalken zu verwenden. Projektionskonvertierung Dies ist ein Vorgang, bei dem das Objekt so korrigiert wird, als ob es von vorne aufgenommen wurde. Ich habe es verwendet, weil ich wollte, dass das zugeschnittene Bild im rechten Winkel ist. Referenzartikel zur Projektionskonvertierung Die Bildkorrektur ist mit der Python / OpenCV-Projektionskonvertierung einfach! | WATLAB -Python, Signalverarbeitung, AI- Versuchen Sie die Projektionsprojektionskonvertierung von Bildern mit OpenCV mit Python --Qiita
Ich verweise auf die folgenden Artikel, um japanische Pfade mit dem Lesen von Bildern kompatibel zu machen. Informationen zum Umgang mit Problemen beim Umgang mit Dateipfaden einschließlich Japanisch in Python OpenCV cv2.imread und cv2.imwrite --Qiita
Die Betriebsmethode ist
Das Ergebnis wird als "./Ergebnisordner / Bilddateiname / Bilddateiname_0, ..." gespeichert. Wenn im Ergebnis derselbe Ordner wie der Dateiname vorhanden ist, wird der Vorgang übersprungen.
Wenn Sie es nicht gut schneiden können, ändern Sie den Schwellenwert oder den Mindestbereich. [Bildschwellenwertverarbeitung - OpenCV-Python-Tutorials 1-Dokumentation](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_thresholding/py_thresholding. html) [Funktionen für Bereiche (Konturen) - Dokumentation zu OpenCV-Python-Tutorials 1](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)
python
import os, shutil, time
from pathlib import Path
import cv2
import numpy as np
from tqdm import tqdm
thresh_value = 240 #Grenzwert beim Binärisieren,Wenn der Pixelwert kleiner als dieser Wert ist, machen Sie ihn weiß(max:255)
minimum_area = 10000 #Verarbeiten Sie keine Objekte, die kleiner als diese sind, wenn die Kontur erfasst wird(Für den Fall, dass andere Punkte als das Zielobjekt erkannt werden)
def imread(filename, flags=cv2.IMREAD_COLOR, dtype=np.uint8):
try:
n = np.fromfile(filename, dtype)
img = cv2.imdecode(n, flags)
return img
except Exception as e:
print(e)
return None
def imwrite(filename, img, params=None):
try:
ext = os.path.splitext(filename)[1]
result, n = cv2.imencode(ext, img, params)
if result:
with open(filename, mode='w+b') as f:
n.tofile(f)
return True
else:
return False
except Exception as e:
print(e)
return False
def calculate_width_height(pts, add):
"""
Breite der erkannten Form,Finden Sie die Höhe mit drei Quadraten
Wenn es zu schräg ist, ändert sich die Form, wenn die Projektion konvertiert wird.
:parameter
------------
pts: numpy.ndarray
Koordinaten von 4 Punkten der extrahierten Form, shape=(4, 1, 2)
add: int
Korrektur, da die Koordinaten des Startpunkts je nach Form unterschiedlich sind
:return
------------
width: int
Berechnete Breite
height: int
Berechnete Höhe
"""
top_left_cood = pts[0 + add][0]
bottom_left_cood = pts[1 + add][0]
bottom_right_cood = pts[2 + add][0]
width = np.int(np.linalg.norm(bottom_left_cood - bottom_right_cood))
height = np.int(np.linalg.norm(top_left_cood - bottom_left_cood))
return width, height
def img_cut():
"""
Bilder im Ressourcenordner(jpg, png)Um den Umriss des Objekts zu erhalten
Schneiden Sie das Objekt aus, projizieren Sie es und bringen Sie es nach vorne
1.Ordner,Datei lesen
2.Bild lesen,Binarisierung(Schwarz und weiß)wird bearbeitet
3.Kontur bekommen
4.Projektionskonvertierung
5.Ausgabe
6.Verschieben Sie die Ressourcendatei zum Ergebnis
:return: None
"""
# 1.Ordner,Datei lesen
resource_folder = Path(r'./resource')
result_folder = Path(r'./result')
#Erstellen, wenn der Ergebnisordner nicht vorhanden ist
if not result_folder.exists():
result_folder.mkdir()
img_list1 = list(resource_folder.glob('*.jpg')) #Pfadliste der JPG-Dateien im Ordner
img_list2 = list(resource_folder.glob('*.jpeg'))
img_list3 = list(resource_folder.glob('*.png'))
img_list = img_list1 + img_list2 + img_list3
for img in img_list:
img_name, img_suffix = img.stem, img.suffix #Holen Sie sich den Bildnamen und die Erweiterung
#Erstellen Sie einen Ordner mit dem Namen der Bilddatei im Ergebnisordner,Überspringen Sie die Konvertierung, wenn derselbe Ordner bereits vorhanden ist
result_img_folder = Path(r'./result/{}'.format(img_name))
if not result_img_folder.exists():
result_img_folder.mkdir()
else:
print('{}Kann nicht konvertiert werden, da ein Ordner mit demselben Namen wie im Ergebnis vorhanden ist'.format(img_name))
continue
# 2.Bild lesen,Binarisierung(Schwarz und weiß)wird bearbeitet
read_img = imread(str(img))
gray_img = cv2.cvtColor(read_img, cv2.COLOR_BGR2GRAY)
ret, thresh_img = cv2.threshold(gray_img, thresh_value, 255, cv2.THRESH_BINARY_INV)
# --------------------------------------------
#Zur binärisierten Bildbestätigung
# cv2.namedWindow('final', cv2.WINDOW_NORMAL)
# cv2.imshow('final', thresh_img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# --------------------------------------------
# 3.Kontur bekommen
# cv2.RETR_EXTERNAL:Extrahieren Sie nur die äußerste Kontur aus den erkannten Konturen->Konturen ignorieren, auch wenn sie sich innerhalb der Kontur befinden
# cv2.CHAIN_APPROX_SIMPLE:Holen Sie sich nur 4 Ecken, nicht die Kanten der Kontur
contours, hierarchy = cv2.findContours(thresh_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
process_cnt = [] #Liste der Konturen, die tatsächlich geschnitten werden sollen
for cnt in contours:
if cv2.contourArea(cnt) < minimum_area: #Schneiden Sie keine Gegenstände, deren Konturfläche zu klein ist
continue
process_cnt.append(cnt)
num = 0
for p_cnt in tqdm(process_cnt[::-1], desc='{}'.format(img_name)): #Aus irgendeinem Grund beginnt der Vorgang mit dem unteren Bild. Schneiden Sie ihn also in umgekehrter Reihenfolge.(Oben)Fix von
x, y, w, h = cv2.boundingRect(p_cnt) #Oben links von Kontur x,y-Koordinate&Breite,Holen Sie sich Höhe
img_half_width = x + w / 2
# cv2.arcLength:Umfangslänge der Kontur,True bedeutet, dass die Kontur geschlossen ist
# cv2.approPolyDP:Ungefähre erkannte Form
epsilon = 0.1 * cv2.arcLength(p_cnt, True)
approx = cv2.approxPolyDP(p_cnt, epsilon, True)
try:
# 4.Projektionskonvertierung
pts1 = np.float32(approx)
if pts1[0][0][0] < img_half_width: #Wenn der Startpunkt der in pts gespeicherten Koordinaten oben links liegt
width, height = calculate_width_height(pts1, 0)
pts2 = np.float32([[0, 0], [0, height], [width, height], [width, 0]])
else:
width, height = calculate_width_height(pts1, 1)
pts2 = np.float32([[width, 0], [0, 0], [0, height], [width, height]])
except IndexError:
continue
M = cv2.getPerspectiveTransform(pts1, pts2)
dst = cv2.warpPerspective(read_img, M, (width, height))
result_img_name = img_name + '_{}.{}'.format(num, img_suffix)
imwrite(str(result_img_folder) + '/' + result_img_name, dst)
num += 1
# 6.Verschieben Sie die Ressourcendatei zum Ergebnis
shutil.move(str(img), result_img_folder)
if __name__ == '__main__':
img_cut()
print('Ende der Ausführung')
time.sleep(3)
python
# cv2.arcLength:Umfangslänge der Kontur,True bedeutet, dass die Kontur geschlossen ist
# cv2.approPolyDP:Ungefähre erkannte Form
epsilon = 0.1 * cv2.arcLength(p_cnt, True)
approx = cv2.approxPolyDP(p_cnt, epsilon, True)
try:
# 4.Projektionskonvertierung
pts1 = np.float32(approx)
Koordinateninformationen von 4 Ecken des Objekts werden in Punkt 1 gespeichert. ex) [[[6181. 598.]]
[[ 145. 656.]]
[[ 135. 3499.]]
[[6210. 3363.]]]
Wenn Sie diese vier Punkte an die Ecken des Bildes bringen, sieht das Bild so aus, als wäre es von vorne gesehen worden.
python
if pts1[0][0][0] < img_half_width: #Wenn der Startpunkt der in pts gespeicherten Koordinaten oben links liegt
width, height = calculate_width_height(pts1, 0)
pts2 = np.float32([[0, 0], [0, height], [width, height], [width, 0]])
else:
width, height = calculate_width_height(pts1, 1)
pts2 = np.float32([[width, 0], [0, 0], [0, height], [width, height]])
Es bestimmt, wo der Startpunkt von pts1 liegt. Da die vier gespeicherten Koordinatenpunkte vom oberen Punkt aus gegen den Uhrzeigersinn gespeichert werden (die y-Achse ist klein), ändert sich der Startpunkt von pts1 abhängig von der Neigung des Bildes. Es wird beurteilt und so eingestellt, dass es den Koordinaten pts2 nach der Projektionskonvertierung entspricht. <img width="400", alt="pts座標.png ", src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779817/f6c5e9a7-d49c-45ca-191e-05efa952f14a.png ">
Die Beurteilungsmethode basiert darauf, ob die x-Koordinate des Startpunkts links oder rechts von der Bildmitte liegt.
Da ich die Form des Objekts so weit wie möglich beibehalten möchte, habe ich die Breite und Höhe anhand von drei Quadraten berechnet und ein zugeschnittenes Bild mit dieser Größe ausgegeben.
Ich wusste nicht, dass sich der Startpunkt von pts1 ändern würde, und zuerst gab ich ein bedeutungsloses Bild aus. Ich konnte es nicht leicht finden, selbst wenn ich im Internet suchte, und am Ende befand ich mich in einem Zustand, in dem ich es schließlich herausfand, indem ich das Bild anstarrte. Ich hoffe, es wird hilfreich sein, wenn es Menschen gibt, die ähnlich in Schwierigkeiten sind.
Lernprogramm [Bildschwellenwertverarbeitung - OpenCV-Python-Tutorials 1-Dokumentation](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_thresholding/py_thresholding. html) Gliederung: Erster Schritt - Dokumentation zu OpenCV-Python-Tutorials 1 ) [Funktionen für Bereiche (Konturen) - Dokumentation zu OpenCV-Python-Tutorials 1](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)
OpenCV-Referenz (Kontur, Bildausschnitt, Projektionskonvertierung) Grundlagen der Konturerkennung aus Bildern mit OpenCV (per findContours-Funktion) | North Building Tech.com [Objekte mit contours-python, image, opencv-contour abrufen und zuschneiden](https://living-sun.com/ja/python/725302-getting-and-cropping-object-in] -images-using-contours-python-image-opencv-contour.html) Versuchen Sie die Projektionsprojektionskonvertierung von Bildern mit OpenCV mit Python --Qiita
Unterstützung für das Lesen von OpenCV-Japanpässen Informationen zum Umgang mit Problemen beim Umgang mit Dateipfaden einschließlich Japanisch in Python OpenCV cv2.imread und cv2.imwrite --Qiita
Berechnungsreferenz für drei Quadrate [Euklidische Entfernung berechnen](http://harmonizedai.com/article/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3% 83% 89% E8% B7% 9D% E9% 9B% A2% E3% 82% 92% E6% B1% 82% E3% 82% 81% E3% 82% 8B /)
Fortschrittsbalkenreferenz Fortschrittsbalken mit tqdm --Qiita anzeigen
Recommended Posts