Text within image in OpenCV - python

I was trying to get some text on an image using OpenCV. But the text is too long for one line and goes out of the image, instead of the next line. I could hardcode the spaces, but I was looking for a more dynamic solution. How do I work around this issue?
def get_text(img, text):
sh = img.shape
txt = np.ones(shape=sh)
fontface = cv2.FONT_HERSHEY_SIMPLEX
fontscale = 1
thickness = 2
color = (0, 0, 0)
orig = (10, 100)
linetype = cv2.LINE_AA
txt = cv2.putText(txt, text, orig, fontface, fontscale, color, thickness, linetype)
txt = txt.astype("uint8")
return txt

import textwrap
def get_text(img, text):
sh = img.shape
txt = np.ones(shape=sh)
fontface = cv2.FONT_HERSHEY_SIMPLEX
fontscale = 1
thickness = 2
color = (0, 0, 0)
orig = (10, 100)
linetype = cv2.LINE_AA
wrapped_text = textwrap.wrap(text, width=35)
x, y = 10, 40
font_size = 1
font_thickness = 2
i = 0
for line in wrapped_text:
textsize = cv2.getTextSize(line, font, font_size, font_thickness)[0]
gap = textsize[1] + 10
y = int((img.shape[0] + textsize[1]) / 2) + i * gap
x = int((img.shape[1] - textsize[0]) / 2)
cv2.putText(img, line, (x, y), font,
font_size,
(0,0,0),
font_thickness,
lineType = cv2.LINE_AA)
txt = txt.astype("uint8")
return txt
Try this, may require some adjustment, but the idea is to use textwrap.wrap(text, width=35).

in this code i simply split string into parts according image width.
# Python program to explain cv2.putText() method
import cv2
import math
import textwrap
path = r'YOUR PATH OF IMAGE'
image = cv2.imread(path)
window_name = 'Image'
font = cv2.FONT_HERSHEY_SIMPLEX
zero= 5
one =50
org = (zero, one)
fontScale = 1
color = (255, 0, 0)
thickness = 2
imageHeight = image.shape[0]
imageWidth = image.shape[1]
print(f"width:",imageWidth)
sizeofnumpix=min(imageWidth,imageHeight)/(25/fontScale)
stringputt = 'YOUR STRING'
i=len(stringputt)
print(i)
if i*sizeofnumpix > imageWidth*2:
n=math.ceil(i*sizeofnumpix/(imageWidth*2))
part_size = math.ceil(i/n)
txt = textwrap.wrap(stringputt, part_size)
for l in txt:
image = cv2.putText(image, l, org, font,fontScale, color, thickness, cv2.LINE_AA)
zero= 5
one = one+math.ceil(sizeofnumpix)
org = (zero, one)
else:
image = cv2.putText(image, stringputt, org, font,fontScale, color, thickness, cv2.LINE_AA)
# Displaying the image
cv2.imwrite('IMGWITHTXT.png',image)

Related

TypeError: ImageDraw.text() got multiple values for argument 'fill'

The about txt file consists of 3 lines. I am passing it as a string to the draw.text function and I have also calculated the width and height of the string in order to correctly position it in the image. However, I am getting the TypeError as mentioned in the title. Here's what I did:
from PIL import Image, ImageFont, ImageDraw
img = Image.new('RGBA', (900, 900), '#EAEAEA')
data = ['About.txt', 'Skills.txt', 'Exp.txt']
name = 1
for elem in data:
with open(elem, 'r') as f:
str1 = ''.join(f.readlines())
font = ImageFont.truetype('AvenirLTStd-Book.otf',16)
ascent, descent = font.getmetrics()
text_width = font.getmask(str1).getbbox()[2]
text_height = font.getmask(str1).getbbox()[3] + descent
draw = ImageDraw.Draw(img)
draw.text((900 - text_width) / 2, (900 - text_height) / 2, str1, font = font, fill = 'black')
img.save(str(name) + '.png')
name += 1

How to draw different language text on the image?

I am doing a project where I need to translate the text into other Indian languages
I have tried few codes but the result I get for languages other than english is empty boxes
Original image:
this is the variable output
[([[217, 25], [1061, 25], [1061, 61], [217, 61]],
'He was in his bedroom: He smelled food, The food smelled',
0.7254911849154941),
([[181, 70], [1006, 70], [1006, 114], [181, 114]],
'like chicken: It smelled good. A neighbor must be cooking',
0.773367181175143),
I am using the output coordinates for drawing a rectangle around the text
1 - first code
image = cv2.imread("/content/drive/MyDrive/image_text_3.jpg")
color = (0, 0, 255)
# Line thickness
thickness = 1
fontpath = "/content/VANAVIL-AvvaiyarRegular.otf"
TEXT_Font = ImageFont.truetype(fontpath, 20)
TEXT_SCALE = 0.85
TEXT_THICKNESS = 1
TEXT = "இனிய பிறந்தநாள் வாழ்த்துக்கள் யோஷினி குட்டி"
for bound in output:
tl, tr, br, bl = bound[0]
tl = (int(tl[0]), int(tl[1]))
tr = (int(tr[0]), int(tr[1]))
br = (int(br[0]), int(br[1]))
bl = (int(bl[0]), int(bl[1]))
cv2.rectangle(image, tl, br, color, thickness)
text_size, _ = cv2.getTextSize(TEXT, TEXT_Font, TEXT_THICKNESS)
text_origin = (tl[0] - text_size[0] / 2, br[1] + text_size[1] / 2)
cv2.putText(image, TEXT, (tl[0], br[1]), TEXT_Font, TEXT_SCALE, (0,255,0), TEXT_THICKNESS, cv2.LINE_AA)
cv2.imwrite('centertext_out.png', image)
This is the error I get for the above code for tamil language
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-103-1d8c09103798> in <module>()
26 cv2.rectangle(image, tl, br, color, thickness)
27
---> 28 text_size, _ = cv2.getTextSize(TEXT, TEXT_SCALE, TEXT_THICKNESS)
29
30 text_origin = (tl[0] - text_size[0] / 2, br[1] + text_size[1] / 2)
TypeError: an integer is required (got type FreeTypeFont)
2 - second code for marathi
fontpath = "/content/Devnew.ttf"
img=cv2.imread('/content/drive/MyDrive/image_text_3.jpg')
b,g,r,a = 0,255,0,0
font = ImageFont.truetype(fontpath, 32)
img_pil = Image.fromarray(img)
draw = ImageDraw.Draw(img_pil)
draw.text((50, 80), "जन्मदिन मुबारक", font = font, fill = (b, g, r, a))
img = np.array(img_pil)
cv2.imwrite('result.png', img)
Result of code 2:
3 - Third code
image = cv2.imread("/content/drive/MyDrive/image_text_3.jpg")
TEXT = "जन्मदिन मुबारक हो योशिनी कुट्टी"
color = (0, 0, 255)
# Line thickness
thickness = 1
b,g,r,a = 0,255,0,0
TEXT_SCALE = 0.9
TEXT_THICKNESS = 1
fontpath = "/content/drive/MyDrive/Devnew.ttf"
font = ImageFont.truetype(fontpath, 20)
img_pil = Image.fromarray(image)
draw = ImageDraw.Draw(img_pil)
draw.text((50, 80), TEXT, font = font, fill =(b,g,r,a))
image = np.array(img_pil)
cv2_imshow(image)
Result of code 3:
I don't understand whether there is a problm with the font file or the code or the image. kindly help in resolving. Thankyou!
My main concern is to put the text inside the rectangle box created in the initial step({cv2.rectangle(image, tl, br, color, thickness} from code 1))
Most likely the problem is with the .otf and .ttf files you are using. Try using the default lohit-tamil fonts from /usr/share/fonts/truetype. They can be installed with sudo apt install fonts-indic if they are not installed already. Use Unicode fonts only or download other Unicode fonts online - e.g. Latha.ttf
import cv2
import numpy as np
from PIL import ImageFont, ImageDraw, Image
img = np.zeros((200,1200,3),np.uint8)
fontpath = "tamil/Latha.ttf"
text = "இனிய பிறந்தநாள் வாழ்த்துக்கள் யோஷினி குட்டி"
font = ImageFont.truetype(fontpath, 32)
img_pil = Image.fromarray(img)
draw = ImageDraw.Draw(img_pil)
draw.text((50, 80),text, font = font)
img_tamil = np.array(img_pil)
cv2.imwrite('tamil.jpg', img_tamil)

problems with overflow from yellow to white

my task is this: having a white sheet, add text to it, embed a picture and make a gradient. I understood how to add text and embed an image. And here's how to make an overflow. for example, from yellow to white or from black to white, I do not understand.I would also like to understand how to move a cloud The final picture should be like this.enter image description here
my code:
import cv2
white_list = cv2.imread('python_snippets/external_data/probe.jpg')
cloud = cv2.imread('python_snippets/external_data/weather_img/cloud.jpg')
white_list[:cloud.shape[0], :cloud.shape[1]] = cloud
font = cv2.FONT_HERSHEY_SIMPLEX
org = (50, 50)
fontScale = 1
color = (255, 0, 0)
thickness = 2
cv2.putText(white_list, '+5', org, font,
fontScale, color, thickness, cv2.LINE_AA)
cv2.imshow('img', white_list)
cv2.waitKey(0)
cv2.destroyAllWindows()
def painting_background(self, color, white_list):
r, g, b = color
for x in range(white_list.shape[1]):
if r < 255:
r += 1
if g < 255:
g += 1
if b < 255:
b += 1
self.white_list[:, x:x + 1] = (r, g, b)
def maker(self, color, degree):
x = 0
y = 400
weather_icon = self.weather_icons[color]
self.painting_background(color, self.white_list)
self.white_list[x:x + weather_icon.shape[0], y:y + weather_icon.shape[1]] = weather_icon
cv2.putText(self.white_list, degree, (360, 150), cv2.FONT_HERSHEY_DUPLEX, 2, (255, 0, 0), 2, cv2.LINE_AA)

How to count an object after passing through the line?

Hey I am new in Python for this level but i am trying my best to do it.
I have detect the object in the video frames and labelled it and also count the total objects in the frame but my question is how can i count the object after passing the line as shown in image. and also with the object category.
Here is my code, please answer in detail and try to add code also.
In the image i have count the total object in the frame but i want to count them when they cross the line
Thanks in advance :)
import cv2
import numpy as np
net = cv2.dnn.readNet('yolov3.weights','yolov3.cfg')
classes = []
with open('coco.names','r') as f:
classes = f.read().splitlines()
# printing the data which is loaded from the names file
#print(classes)
cap = cv2.VideoCapture('video.mp4')
while True:
_,img = cap.read()
height, width, _ = img.shape
blob = cv2.dnn.blobFromImage(img, 1/255, (416 , 416), (0,0,0) ,swapRB=True,crop=False)
net.setInput(blob)
output_layer_names = net.getUnconnectedOutLayersNames()
layerOutput = net.forward(output_layer_names)
boxes = []
person =0
truck =0
car = 0
confidences = []
class_ids =[]
for output in layerOutput:
for detection in output:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
center_x = int(detection[0]*width)
center_y = int(detection[1]*height)
w = int(detection[2]*width)
h = int(detection[3]*height)
x = int(center_x - w/2)
y = int(center_y - h/2)
boxes.append([x,y,w,h])
confidences.append((float(confidence)))
class_ids.append(class_id)
indexes = cv2.dnn.NMSBoxes(boxes,confidences,0.5,0.4)
font = cv2.QT_FONT_NORMAL
colors = np.random.uniform(0,255,size=(len(boxes),3))
for i in indexes.flatten():
labelsss = str(classes[class_ids[i]])
if(labelsss == 'person'):
person+=1
if(labelsss == 'car'):
car+=1
if(labelsss == 'truck'):
truck+=1
for i in indexes.flatten():
x,y,w,h = boxes[i]
label =str(classes[class_ids[i]])
confidence = str(round(confidences[i],1))
color = colors[i]
cv2.rectangle(img,(x,y),(x+w , y+h), color, 2)
cv2.line(img,(1000,250),(5,250),(0,0,0),2)
cv2.putText(img, label + " ", (x, y+20), font, 0.5, (255,255,255),2)
cv2.putText(img, 'Car'+ ":" + str(car), (20, 20), font, 0.8, (0,0,0),2)
cv2.putText(img, 'Person'+ ":" + str(person), (20, 50), font, 0.8, (0,0,0),2)
cv2.putText(img, 'Truck'+ ":" + str(truck), (20, 80), font, 0.8, (0,0,0),2)
cv2.imshow('Image',img)
key = cv2.waitKey(1)
if key == 10:
break
cap.release()
cv2.destroyAllWindows()
I did a project just like this during my internship. You can check out the code here: https://github.com/sarimmehdi/nanonets_object_tracking/blob/master/test_on_video.py
In a nutshell: You should instead draw a rectangle (narrow) and count a tracked ID when it passes through the rectangle. If the rectangle is just narrow enough, you can also avoid the problem of re-identification.

How to wrap text in OpenCV when I print it on an image and it exceeds the frame of the image?

I have a 1:1 ratio image and I want to make sure that if the text exceeds the frame of the image, it gets wrapped to the next line.
How would I do it?
I am thinking of doing an if-else block, where "if sentence exceeds x characters->new line" but I'm not sure how to implement it.
import numpy as np
import cv2
img = cv2.imread('images/1.png')
print(img.shape)
height, width, channel = img.shape
text_img = np.ones((height, width))
print(text_img.shape)
font = cv2.FONT_HERSHEY_SIMPLEX
text = "Lorem Ipsum "
textsize = cv2.getTextSize(text, font, 2, 2)[0]
font_size = 1
font_thickness = 2
for i, line in enumerate(text.split('\n')):
textsize = cv2.getTextSize(line, font, font_size, font_thickness)[0]
gap = textsize[1] + 10
y = int((img.shape[0] + textsize[1]) / 2) + i * gap
x = int((img.shape[1] - textsize[0]) / 2)
cv2.putText(img, line, (x, y), font,
font_size,
(0,0,0),
font_thickness,
lineType = cv2.LINE_AA)
cv2.imshow("Result Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
You can use textwrap to wrap text in OpenCV.
import numpy as np
import cv2
import textwrap
img = cv2.imread('apple.png')
print(img.shape)
height, width, channel = img.shape
text_img = np.ones((height, width))
print(text_img.shape)
font = cv2.FONT_HERSHEY_SIMPLEX
text = "Lorem Ipsum dgdhswjkclyhwegflhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhvhasvcxsbvfajhskvfgsdj"
wrapped_text = textwrap.wrap(text, width=35)
x, y = 10, 40
font_size = 1
font_thickness = 2
for i, line in enumerate(wrapped_text):
textsize = cv2.getTextSize(line, font, font_size, font_thickness)[0]
gap = textsize[1] + 10
y = int((img.shape[0] + textsize[1]) / 2) + i * gap
x = int((img.shape[1] - textsize[0]) / 2)
cv2.putText(img, line, (x, y), font,
font_size,
(0,0,0),
font_thickness,
lineType = cv2.LINE_AA)
cv2.imshow("Result Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Below is the output image without using textwrap(running your code):
Below is the output image using textwrap(my code):
There are many other ways you can achieve the same but textwrap is certainly one way of doing so in OpenCV and is simple too.

Categories