[PYTHON] Machen Sie die Funktion zum Zeichnen japanischer Schriftarten in OpenCV allgemein

Einführung

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.

Verbesserung

Über RGB und BGR

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.

Elegantere Umkehrung der Farbreihenfolge

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.

Es ist auch nicht erforderlich, die Farbreihenfolge umzukehren

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.

Über den ROI

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. cv_jp_font_test_4.png

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

Entsprechung zur Darstellung außerhalb des Bildes

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?

  1. Erhalten Sie die Textbeschreibungsgröße im Voraus und erstellen Sie ein monochromes Bild dieser Größe ①
  2. Überprüfen Sie, ob es hervorsteht, wenn es an der angegebenen Position auf dem Originalbild platziert wird Tun Sie nichts, wenn der Textbereich vollständig außerhalb des Bildes liegt
  3. Ersetzen Sie das monochromatische Bild ganz oder teilweise durch das Originalbild ②
  4. Zeichnen Sie Text mit PIL Die Helligkeit von R und die Helligkeit von B sind vertauscht, aber es gibt kein Problem, wenn Sie es nicht anzeigen ③
  5. Kehren Sie zu OpenCV ④ zurück
  6. Schneiden Sie nur den Bereich ab, in dem sich das Originalbild befand ⑤
  7. Aktualisieren Sie die entsprechende Zelle des Originalbilds auf die mit den gezeichneten Zeichen 6
1.png 2.png 3.png 4.png 5.png
cv_jp_font_test_7.png

Zusätzliche Funktionen

Machen Sie das Zeichnen möglich, indem Sie die Koordinaten oben rechts und in der Mitte sowie unten links angeben

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. cv_jp_font_test_8.png

Kippen Sie die Buchstaben, um sie zu beschreiben

Bitte lass mich gehen.

Eine Funktion, die das oben Genannte beinhaltet

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. cv_jp_font_test_9.png

Am Ende

Wir möchten kounoike für die Kommentare im vorherigen Artikel und Qiita für die Bereitstellung dieser Gelegenheit danken.

Recommended Posts

Machen Sie die Funktion zum Zeichnen japanischer Schriftarten in OpenCV allgemein
Erstellen Sie mit OpenCV eine Funktion zum Beschreiben japanischer Schriftarten
Holen Sie sich den Aufrufer einer Funktion in Python
Kopieren Sie die Liste in Python
Korrigieren Sie die Argumente der in map verwendeten Funktion
Machen Sie den Fortschritt von dd in der Fortschrittsanzeige sichtbar
Zeichnen auf Jupyter mit der Plot-Funktion von Pandas
Vergleichen Sie die Schriftarten von Jupyter-Themen
Lassen Sie das Gleichungsdiagramm der linearen Funktion in Python zeichnen
Sortieren Sie das String-Array nach Länge und japanischer Silbe
Stellen Sie Opencv in Python zur Verfügung
Vorsichtsmaßnahmen bei der Überlagerung der Wahrscheinlichkeitsdichtefunktion und des Histogramms in matplotlib
Machen Sie den SIP-Server so kurz wie möglich (in der Mitte der Erklärung).
Versuchen Sie, die stochastische Massenfunktion der Binomialverteilung in Python zu transkribieren
Erstellen Sie eine Funktion, um den Inhalt der Datenbank in Go abzurufen
Sortierwarnung in der Funktion pd.concat
Japanische Übersetzung des e2fsprogs-Handbuchs
Die Geschichte der Teilnahme an AtCoder
Implementierung der Login-Funktion in Django
Japanische Übersetzung des man-db Handbuchs
Machen Sie matplotlib in 3 Minuten mit Japanisch kompatibel
Japanische Übersetzung des Util-Linux-Handbuchs
Japanische Übersetzung des iproute2-Handbuchs
[OpenCV; Python] Zusammenfassung der Funktion findcontours
Suchen Sie den Namen und die Daten einer freien Variablen in einem Funktionsobjekt
Machen Sie es sichtbar, indem Sie die von journalctrl abgeschnittene Linie durchbrechen
[Verständnis in 3 Minuten] Der Beginn von Linux
Überprüfen Sie das Verhalten des Zerstörers in Python
Die Geschichte eines Fehlers in PyOCR
Vergleich japanischer Konvertierungsmodule in Python3
Implementieren Sie einen Teil des Prozesses in C ++
Nehmen Sie die logische Summe von List in Python (Zip-Funktion)
[Python3] Schreiben Sie das Codeobjekt der Funktion neu
Das Ergebnis der Installation von Python auf Anaconda
R: Verwenden Sie im Skript Japanisch anstelle von Japanisch
Über die Argumente der Setup-Funktion von PyCaret
Grundlagen zum Ausführen von NoxPlayer in Python
Über japanische Schriften von matplotlib (für Mac)
Unterschied in der Ausgabe der Fensterfunktion mit gerader Länge
Auf der Suche nach dem schnellsten FizzBuzz in Python
Der hintere Schrägstrich der japanischen Tastatur ist "ro".
Machen Sie den Standardwert des Arguments unveränderlich
Japanische Übersetzung: PEP 20 - Das Zen von Python
[Linux] Unterschied in den Zeitinformationen in Abhängigkeit von der Uhr-ID der Funktion clock_gettime ()
Holen Sie sich das Ergebnis der umgekehrten GeoCoding auf Japanisch mit dem Java SDK von GoogleMapsAPI.
[AWS] Lassen Sie uns einen Komponententest der Lambda-Funktion in der lokalen Umgebung durchführen
Legen Sie die Obergrenze für die Anzahl der Wiederholungen rekursiver Funktionen in Python fest
Holen Sie sich mit Python den Aktienkurs eines japanischen Unternehmens und erstellen Sie eine Grafik
So stellen Sie die Schriftbreite des in pyenv eingegebenen Jupyter-Notizbuchs gleich