J'ai reçu un commentaire dans l'article précédent "Fonctionnalisation de la représentation des polices japonaises avec OpenCV" (https://qiita.com/mo256man/items/82da5138eeacc420499d). Je suis très reconnaissant. De plus, l'endroit où j'ai sauté est clairement visible. Je dois faire de mon mieux pour cela.
La cible est une fonction qui peut décrire le japonais de la même manière que cv2.imshow ()
, donc la couleur spécifiée est la séquence d'OpenCV (BGR).
Dans l'article précédent, lorsque je travaillais avec PIL dans une fonction, je l'ai converti en une séquence de couleurs PIL (RVB). L'image a également été convertie de BGR en RVB, le japonais a été représenté à l'aide de la fonction PIL, renvoyé à BGR, puis reconverti en OpenCV.
Concernant l'inversion de l'ordre des couleurs Dans ce qui précède, la méthode d'implémentation non élégante consistant à retirer chaque élément et à changer l'ordre a été utilisée, mais il semble que les tranches peuvent être utilisées normalement.
python
>>> (255, 0, 128)[::-1]
(128, 0, 255)
Quoi? J'aurais dû essayer cela après de nombreux essais et erreurs.
alors. À la condition que vous compreniez la relation entre BGR et RVB. Si vous ne convertissez pas l'image dans la couleur correcte pour PIL, dessinez la séquence qui devrait être RVB comme couleur de texte avec PIL comme BGR et renvoyez-la à OpenCV telle quelle, ce sera la couleur correcte comme OpenCV en conséquence. C'est rapide, n'est-ce pas? C'est le but de la personne qui a commenté. Quand je l'ai soumis au professeur de l'école comme devoir, il a dit: "Je vous ai dit qu'OpenCV et PIL avaient la séquence de couleurs opposée. Cela semble être la bonne réponse mais la mauvaise formule au milieu." C'est une technique qui semble être dite, mais la programmation nécessite ce genre d'idée. Non, je l'ai aussi inventé. Cependant, je ne l'ai pas beaucoup intégré car je ne pouvais pas utiliser la fonction qui convertit OpenCV et PIL que j'ai créée. Excusez-moi.
Alors comparons la troisième fonction que vous avez publiée avec ma deuxième fonction.
python
#Fonction d'origine
def cv2_putText_2(img, text, org, fontFace, fontScale, color):
x, y = org
b, g, r = color #Cette phrase est inutile car la couleur reste BGR
colorRGB = (r, g, b) #Cette phrase est inutile car la couleur reste BGR. N'utilisez même pas de tranches
imgPIL = cv2pil(img) #Le processus de conversion simple de la fonction originale de conversion de la couleur en PIL en 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) #La couleur est l'argument de la fonction telle qu'elle est
imgCV = pil2cv(imgPIL) #Sans reconversion des couleurs
return imgCV #La valeur de retour est simplement convertie en OpenCV.
# ↓↓↓↓↓↓
#La fonction que vous avez publiée
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)
Eh bien, c'est bien simple.
ROI (Region of Interest) se traduit par une région d'intérêt et signifie une zone d'intérêt à traiter dans toute l'image. [Cet article](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 Il est également utilisé dans% 82% A4% E3% 82% AF).
Le commentaire suivant est que si vous obtenez la taille du texte à dessiner à l'avance et PIL seulement la partie de l'image originale où les caractères sont dessinés, ce sera beaucoup plus rapide que PILing l'image originale entière. Je ne pense pas que les gens intelligents soient ...
Cependant, vous avez besoin d'un objet ʻImageDraw.Drawpour utiliser ʻImageDraw.textsize ()
de PIL. Si vous ne connaissez pas la taille, pouvez-vous créer une image monochrome de base? Ça n'existe pas. Même si le texte est trop petit pour être dessiné, tout ce que vous avez à faire est de préparer l'objet ʻImageDraw.Draw`.
Lisons la quatrième fonction publiée sur cette base.
python
def cv2_putText_4(img, text, org, fontFace, fontScale, color):
x, y = org
fontPIL = ImageFont.truetype(font = fontFace, size = fontScale)
#Taille(0,0)Créer une image solide et créer son objet Draw
dummy_draw = ImageDraw.Draw(Image.new("RGB", (0,0)))
#Obtient la largeur et la hauteur du rectangle lors du dessin de la phrase spécifiée avec la taille de police spécifiée
w, h = dummy_draw.textsize(text, font = fontPIL)
"""
Je l'ajouterai ici plus tard
"""
#Découpez une partie de l'image originale à la taille que vous venez d'obtenir et ne faites que cette partie en image PIL
imgPIL = Image.fromarray(img[y-h:y,x:x+w,:])
#Créez-lui un objet Draw
draw = ImageDraw.Draw(imgPIL)
#La norme est qu'il a été coupé pour dessiner à nouveau les caractères.(0,0)
draw.text(xy = (0,0), text = text, fill = color, font = fontPIL)
#Rognage inversé Remplacez la partie pertinente de l'image d'origine par une image illustrée par un personnage
img[y-h:y,x:x+w,:] = np.array(imgPIL, dtype = np.uint8)
return img
Hé, je vois. Cependant, à cause d'un bug dans ʻImageDraw.textsize () `, si vous utilisez la hauteur obtenue telle quelle, le fond sera un peu coupé.
Alors que feriez-vous? Nous devrions étendre ce retour sur investissement à texto. Comme ça.
python
b = int(0.1 * h) #Réglez la hauteur à sécuriser sous la ligne de base de manière appropriée
# imgPIL = Image.fromarray(img[y-h:y,x:x+w,:]) #À
imgPIL = Image.fromarray(img[y-h:y+b,x:x+w,:]) #À
Puisque l'image OpenCV est stockée sous la forme numpy.ndarray, vous pouvez extraire une partie en la rognant en écrivant ʻimg [y: y + h, x: x + w] . C'est l'un des faits les plus émouvants que j'ai appris sur OpenCV, et je l'ai écrit encore et encore. Cependant, cela a ses inconvénients. Bien entendu, puisqu'il s'agit d'un tableau, il n'est pas possible de spécifier en dehors de l'image. Bien sûr, les fonctions
cv2.putText ()` et de dessin graphique fournies par OpenCV sont conçues pour qu'il n'y ait aucun problème même si elles s'étendent en dehors de l'image d'origine, mais ma fonction est une erreur à ce stade. Je dois bien le couper.
Je n'ai pas écrit sur le rognage PIL dans mon article, mais contrairement à OpenCV, vous pouvez spécifier en dehors de la plage d'image. https://note.nkmk.me/python-pillow-image-crop-trimming/ Cependant, il m'a montré comment spécifier le retour sur investissement dans le commentaire, et il semble que rendre l'image entière PIL pour le rognage semble aller à l'encontre de l'idée jusqu'à présent, et j'étudiais OpenCV en premier lieu. Je ne veux pas utiliser le rognage PIL.
Et cette façon de penser?
① | ② | ③ | ④ | ⑤ |
---|---|---|---|---|
⑥ |
---|
Le but depuis le début était de pouvoir gérer les polices japonaises de la même manière que cv2.putText ()
, mais je voulais ajouter une autre fonction.
Les coordonnées spécifiées par * org * dans cv2.putText ()
sont en bas à gauche du caractère. Comme je l'ai écrit la dernière fois, je pense que c'est difficile à utiliser.
Par conséquent, il est maintenant possible de spécifier si les coordonnées spécifiées par * org * sont en bas à gauche comme dans cv2.putText ()
, en haut à gauche comme dans PIL ou au centre.
L'image ci-dessous montre que la même coordonnée y est spécifiée dans la fonction d'origine (la coordonnée y de cv2.MARKER_STAR
est la même), mais elle est dessinée à des hauteurs différentes en raison de paramètres différents. ..
De la gauche, le même standard inférieur gauche que cv2.putText ()
, le standard supérieur droit équivalent à ʻImageDraw.text () `de PIL et le standard central.
S'il vous plait, laissez-moi partir.
Avec exemple de programme.
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()Argument d'origine "mode" qui n'est pas dans le standard de coordonnées spécifié par org
#0 (par défaut) = cv2.putText()Identique au coin inférieur gauche 1 = supérieur gauche 2 = centre
#Obtenir la zone de description textuelle
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) #Contre-mesures pour le montant qui dépasse ci-dessous en raison d'un bug
#Obtenez les coordonnées en haut à gauche de la zone de description du texte (à partir du coin supérieur gauche de l'image d'origine)
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]
#Ne rien faire en dehors de l'écran
if not ((-text_w < x0 < img_w) and (-text_b-text_h < y0 < img_h)) :
print ("out of bounds")
return img
#En haut à gauche et en bas à droite de la zone où se trouve l'image d'origine dans la zone de description textuelle (le coin supérieur gauche de l'image d'origine est l'origine)
x1, y1 = max(x0, 0), max(y0, 0)
x2, y2 = min(x0+text_w, img_w), min(y0+text_h+text_b, img_h)
#Créez une image noire de la même taille que la zone de description de texte et collez l'image d'origine sur tout ou partie de celle-ci
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]
#Convertissez-le en PIL, spécifiez la police et dessinez le texte (pas de conversion de couleur)
imgPIL = Image.fromarray(text_area)
draw = ImageDraw.Draw(imgPIL)
draw.text(xy = (0, 0), text = text, fill = color, font = fontPIL)
#Convertir l'image PIL en image OpenCV (pas de conversion de couleur)
text_area = np.array(imgPIL, dtype = np.uint8)
#Mettez à jour la zone correspondante de l'image originale avec celle avec les caractères dessinés
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 = "Japonais aussi\n possible"
color = (255,0,0)
positions = [(-imgW,-imgH), #Ceci est en dehors de l'image et n'est pas représenté
(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, #J'ai spécifié les mêmes coordonnées que le centre du cercle
fontFace = fontPIL,
fontScale = size,
color = color,
mode = 2) #Les coordonnées que vous venez de spécifier sont le centre de la zone de description des caractères.
cv2.imshow("", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
Quoi que je fasse par moi-même, le standard central est compatible avec cv2.circle ()
et semble être utile.
Nous tenons à remercier kounoike pour ses commentaires dans l'article précédent et Qiita pour cette opportunité.
Recommended Posts