Ich habe im vorherigen Artikel "Funktionalisieren der Darstellung japanischer Schriftarten mit OpenCV" (https://qiita.com/mo256man/items/82da5138eeacc420499d) einen Kommentar erhalten. Ich bin sehr dankbar. Außerdem ist der Ort, an dem ich übersprungen habe, deutlich zu sehen. Dafür muss ich mein Bestes geben.
Das Ziel ist eine Funktion, die Japanisch auf die gleiche Weise wie "cv2.imshow ()" beschreiben kann. Die angegebene Farbe ist also die Reihenfolge von OpenCV (BGR). Im vorherigen Artikel habe ich bei der Arbeit mit PIL in einer Funktion diese in eine PIL-Farbsequenz (RGB) konvertiert. Das Bild wurde auch von BGR in RGB konvertiert, Japanisch wurde mit der PIL-Funktion dargestellt, in BGR zurückgegeben und dann wieder in OpenCV konvertiert.
In Bezug auf die Umkehrung der Farbreihenfolge Oben wurde die nicht elegante Implementierungsmethode zum Herausnehmen jedes Elements und zum Ändern der Reihenfolge verwendet, aber es scheint, dass Slices normal verwendet werden können.
python
>>> (255, 0, 128)[::-1]
(128, 0, 255)
Was? Ich hätte es nach viel Versuch und Irrtum versuchen sollen.
damit. Unter der Bedingung, dass Sie die Beziehung zwischen BGR und RGB verstehen. Wenn Sie das Bild nicht in die richtige Farbe für PIL konvertieren, zeichnen Sie die Sequenz, die RGB als Textfarbe mit PIL als BGR sein soll, und geben Sie sie so wie sie ist an OpenCV zurück. Dadurch wird die richtige Farbe als OpenCV angezeigt. Es ist schnell, nicht wahr? Das ist der Zweck der Person, die kommentiert hat. Als ich es dem Schullehrer als Auftrag vorlegte, sagte er: "Ich habe Ihnen gesagt, dass OpenCV und PIL die entgegengesetzte Farbsequenz haben. Dies scheint die richtige Antwort zu sein, aber die falsche Formel in der Mitte." Es ist eine Technik, die gesagt zu werden scheint, aber das Programmieren erfordert diese Art von Idee. Nein, ich habe es mir auch ausgedacht. Ich habe es jedoch nicht so oft integriert, weil ich die von mir erstellte Funktion zum Konvertieren von OpenCV und PIL nicht verwenden konnte. Entschuldigung.
Vergleichen wir also die dritte Funktion, die Sie gepostet haben, mit meiner zweiten Funktion.
python
#Ursprüngliche Funktion
def cv2_putText_2(img, text, org, fontFace, fontScale, color):
x, y = org
b, g, r = color #Dieser Satz ist nicht erforderlich, da die Farbe BGR bleibt
colorRGB = (r, g, b) #Dieser Satz ist nicht erforderlich, da die Farbe BGR bleibt. Verwenden Sie nicht einmal Scheiben
imgPIL = cv2pil(img) #Der Vorgang des einfachen Konvertierens der ursprünglichen Funktion des Konvertierens der Farbe in PIL in PIL
draw = ImageDraw.Draw(imgPIL)
fontPIL = ImageFont.truetype(font = fontFace, size = fontScale)
w, h = draw.textsize(text, font = fontPIL)
draw.text(xy = (x,y-h), text = text, fill = colorRGB, font = fontPIL) #Die Farbe ist das Argument der Funktion, wie sie ist
imgCV = pil2cv(imgPIL) #Ohne Farbumwandlung
return imgCV #Der Rückgabewert wird einfach in OpenCV konvertiert.
# ↓↓↓↓↓↓
#Die Funktion, die Sie gepostet haben
def cv2_putText_3(img, text, org, fontFace, fontScale, color):
x, y = org
imgPIL = Image.fromarray(img)
draw = ImageDraw.Draw(imgPIL)
fontPIL = ImageFont.truetype(font = fontFace, size = fontScale)
w, h = draw.textsize(text, font = fontPIL)
draw.text(xy = (x,y-h), text = text, fill = color, font = fontPIL)
return np.array(imgPIL, dtype = np.uint8)
Nun, es ist schön einfach.
ROI (Region of Interest) wird als Region of Interest übersetzt und bezeichnet einen Bereich von Interesse für die Verarbeitung im gesamten Bild. [Dieser Artikel](https://qiita.com/mo256man/items/c570c645153cae122196#%E5%BF%9C%E7%94%A8%E4%BE%8B2%E9%A1%94%E6%A4%9C % E5% 87% BA% E3% 81% A8% E9% 80% A3% E5% 8B% 95% E3% 81% 97% E3% 81% 9F% E3% 83% A2% E3% 82% B6% E3 Es wird auch in% 82% A4% E3% 82% AF verwendet.
Der nächste Kommentar lautet: Wenn Sie die Größe des zu zeichnenden Textes im Voraus erhalten und nur den Teil des Originalbilds PILEN, in dem die Zeichen gezeichnet werden, ist dies viel schneller als das PILen des gesamten Originalbilds. Ich glaube nicht, dass kluge Leute ... Sie benötigen jedoch ein ImageDraw.Draw-Objekt, um PILs ImageDraw.textsize () verwenden zu können. Wenn Sie die Größe nicht kennen, können Sie ein monochromes Basisbild erstellen? Nicht so etwas. Selbst wenn der Text zu klein ist, um gezeichnet zu werden, müssen Sie nur das Objekt "ImageDraw.Draw" vorbereiten.
Lesen wir die vierte Funktion, die darauf basiert.
python
def cv2_putText_4(img, text, org, fontFace, fontScale, color):
x, y = org
fontPIL = ImageFont.truetype(font = fontFace, size = fontScale)
#Größe(0,0)Erstellen Sie ein festes Bild von und erstellen Sie das Draw-Objekt
dummy_draw = ImageDraw.Draw(Image.new("RGB", (0,0)))
#Ruft die Breite und Höhe des Rechtecks ab, wenn der angegebene Satz mit der angegebenen Schriftgröße gezeichnet wird
w, h = dummy_draw.textsize(text, font = fontPIL)
"""
Ich werde es später hier hinzufügen
"""
#Schneiden Sie einen Teil des Originalbilds auf die gerade erhaltene Größe und machen Sie nur diesen Teil zu einem PIL-Bild
imgPIL = Image.fromarray(img[y-h:y,x:x+w,:])
#Erstellen Sie ein Draw-Objekt dafür
draw = ImageDraw.Draw(imgPIL)
#Der Standard ist, weil es getrimmt wurde, um die Zeichen wieder zu zeichnen.(0,0)
draw.text(xy = (0,0), text = text, fill = color, font = fontPIL)
#Reverse Trimmen Ersetzen Sie den relevanten Teil des Originalbilds durch ein Bild mit Zeichen
img[y-h:y,x:x+w,:] = np.array(imgPIL, dtype = np.uint8)
return img
Hey, ich verstehe. Aufgrund eines Fehlers in "ImageDraw.textsize ()" wird der Boden ein wenig abgeschnitten, wenn Sie die erhaltene Höhe unverändert verwenden.
Was würdest du dann tun? Wir sollten diesen ROI auf Texto ausweiten. So was.
python
b = int(0.1 * h) #Stellen Sie die zu sichernde Höhe unter der Grundlinie entsprechend ein
# imgPIL = Image.fromarray(img[y-h:y,x:x+w,:]) #Zu
imgPIL = Image.fromarray(img[y-h:y+b,x:x+w,:]) #Zu
Da das OpenCV-Bild in Form von numpy.ndarray gespeichert ist, können Sie einen Teil durch Trimmen extrahieren, indem Sie "img [y: y + h, x: x + w]" schreiben. Dies ist eine der bewegendsten Fakten, die ich über OpenCV gelernt habe, und ich habe sie immer wieder geschrieben. Dies hat jedoch seine Nachteile. Da es sich um ein Array handelt, ist es natürlich nicht möglich, außerhalb des Bildes anzugeben. Natürlich sind die von OpenCV bereitgestellten Funktionen "cv2.putText ()" und "Grafikdarstellung" so konzipiert, dass es kein Problem gibt, auch wenn sie sich außerhalb des Originalbilds erstrecken, aber meine Funktion ist an dieser Stelle ein Fehler. Ich muss es gut schneiden.
Ich habe in meinem Artikel nicht über das PIL-Trimmen geschrieben, aber im Gegensatz zu OpenCV können Sie außerhalb des Bildbereichs angeben. https://note.nkmk.me/python-pillow-image-crop-trimming/ Er hat mir jedoch gezeigt, wie man den ROI im Kommentar spezifiziert, und es scheint, dass das Erstellen des gesamten Bild-PIL zum Trimmen gegen die bisherige Idee zu verstoßen scheint, und ich habe zunächst OpenCV studiert. Ich möchte kein PIL-Trimmen verwenden.
Wie wäre es mit dieser Denkweise?
① | ② | ③ | ④ | ⑤ |
---|---|---|---|---|
⑥ |
---|
Der Zweck von Anfang an war es, japanische Schriftarten auf die gleiche Weise wie "cv2.putText ()" behandeln zu können, aber ich wollte eine weitere Funktion hinzufügen.
Die von * org * in cv2.putText ()
angegebenen Koordinaten befinden sich unten links im Zeichen. Wie ich letztes Mal schrieb, denke ich, dass dies schwierig zu verwenden ist.
Daher kann jetzt angegeben werden, ob die durch * org * angegebenen Koordinaten unten links wie bei cv2.putText ()
, oben links wie bei PIL oder in der Mitte sein sollen.
Das Bild unten zeigt, dass in der ursprünglichen Funktion dieselbe y-Koordinate angegeben ist (die y-Koordinate von cv2.MARKER_STAR
ist dieselbe), jedoch aufgrund unterschiedlicher Einstellungen in unterschiedlichen Höhen gezeichnet wird. ..
Von links derselbe untere linke Standard wie "cv2.putText ()", der obere rechte Standard, der PILs "ImageDraw.text ()" entspricht, und der mittlere Standard.
Bitte lass mich gehen.
Mit Beispielprogramm.
python
import numpy as np
import cv2
from PIL import Image, ImageDraw, ImageFont
def cv2_putText_5(img, text, org, fontFace, fontScale, color, mode=0):
# cv2.putText()Ursprüngliches Argument "Modus", das nicht im von org angegebenen Koordinatenstandard enthalten ist
#0 (Standard) = cv2.putText()Gleich wie unten links 1 = oben links 2 = Mitte
#Textbeschreibungsbereich abrufen
fontPIL = ImageFont.truetype(font = fontFace, size = fontScale)
dummy_draw = ImageDraw.Draw(Image.new("RGB", (0,0)))
text_w, text_h = dummy_draw.textsize(text, font=fontPIL)
text_b = int(0.1 * text_h) #Gegenmaßnahmen für den Betrag, der aufgrund eines Fehlers unten herausragt
#Holen Sie sich die oberen linken Koordinaten des Textbeschreibungsbereichs (beginnen Sie oben links im Originalbild)
x, y = org
offset_x = [0, 0, text_w//2]
offset_y = [text_h, 0, (text_h+text_b)//2]
x0 = x - offset_x[mode]
y0 = y - offset_y[mode]
img_h, img_w = img.shape[:2]
#Tun Sie nichts außerhalb des Bildschirms
if not ((-text_w < x0 < img_w) and (-text_b-text_h < y0 < img_h)) :
print ("out of bounds")
return img
#Oben links und unten rechts im Bereich, in dem sich das Originalbild befindet, im Textbeschreibungsbereich (oben links im Originalbild ist der Ursprung).
x1, y1 = max(x0, 0), max(y0, 0)
x2, y2 = min(x0+text_w, img_w), min(y0+text_h+text_b, img_h)
#Erstellen Sie ein schwarzes Bild mit der gleichen Größe wie der Textbeschreibungsbereich und fügen Sie das Originalbild ganz oder teilweise ein
text_area = np.full((text_h+text_b,text_w,3), (0,0,0), dtype=np.uint8)
text_area[y1-y0:y2-y0, x1-x0:x2-x0] = img[y1:y2, x1:x2]
#Konvertieren Sie es in PIL, geben Sie die Schriftart an und zeichnen Sie den Text (keine Farbkonvertierung)
imgPIL = Image.fromarray(text_area)
draw = ImageDraw.Draw(imgPIL)
draw.text(xy = (0, 0), text = text, fill = color, font = fontPIL)
#PIL-Bild wieder in OpenCV-Bild konvertieren (keine Farbkonvertierung)
text_area = np.array(imgPIL, dtype = np.uint8)
#Aktualisieren Sie den entsprechenden Bereich des Originalbilds auf den mit den gezeichneten Zeichen
img[y1:y2, x1:x2] = text_area[y1-y0:y2-y0, x1-x0:x2-x0]
return img
def main():
img = np.full((200,400,3), (160,160,160), dtype=np.uint8)
imgH, imgW = img.shape[:2]
fontPIL = "Dflgs9.TTC" #DF Reiga Song
size = 30
text = "Japanisch auch\n möglich"
color = (255,0,0)
positions = [(-imgW,-imgH), #Dies befindet sich außerhalb des Bildes und ist nicht dargestellt
(0,0), (0,imgH//2), (0,imgH),
(imgW//2,0), (imgW//2,imgH//2), (imgW//2,imgH),
(imgW,0), (imgW,imgH//2), (imgW,imgH)]
for pos in positions:
img = cv2.circle(img, pos, 60, (0,0,255), 3)
img = cv2_putText_5(img = img,
text = text,
org = pos, #Ich habe die gleichen Koordinaten wie der Mittelpunkt des Kreises angegeben
fontFace = fontPIL,
fontScale = size,
color = color,
mode = 2) #Die soeben angegebenen Koordinaten bilden die Mitte des Zeichenbeschreibungsbereichs.
cv2.imshow("", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
Was auch immer ich selbst gemacht habe, der zentrale Standard ist kompatibel mit cv2.circle ()
und scheint nützlich zu sein.
Wir möchten kounoike für die Kommentare im vorherigen Artikel und Qiita für die Bereitstellung dieser Gelegenheit danken.
Recommended Posts