Reputation: 377
I have been trying to write text to an 80x80 16-bit grayscale image and have been having some trouble getting it to work.
I am currently using:
image = im[0]/255.0 #where im is just an np array of images (which are 80x80 np arrays)
# font
font = cv2.FONT_HERSHEY_SIMPLEX
# org
org = (40, 15)
# fontScale
fontScale = 0.3
# Blue color in BGR
color = (255.0)
# Line thickness of 2 px
thickness = 1
# Using cv2.putText() method
image = cv2.putText(image, 'Out:16', org, font, fontScale, color, thickness, cv2.LINE_AA)
# Displaying the image
cv2.imshow(window_name, image)
However, not only does the text look pretty awe full and take up a lot of space (I cant go lower without it not being legible), the images becomes all black except of the text which is white.
Would there be a better way to write text to a low resolution image (make the text smaller)? And why is the image turned to all black?
EDIT:
I tried using ImageDraw() and the result is all greyed
from PIL import Image, ImageFont, ImageDraw
# creating a image object
image = Image.fromarray(im[0]/255.0)
draw = ImageDraw.Draw(image)
# specified font size
font = ImageFont.truetype('./arial.ttf', 10)
text = 'fyp:16'
# drawing text size
draw.text((5, 5), text, font = font, align ="left")
Upvotes: 1
Views: 2108
Reputation: 32094
It looks like the main issue is converting image type to float
.
Assume (please verify it):
im[0]
is 16-bit grayscale, and im[0].dtype
is dtype('uint16')
.
image = im[0]/255.0
implies that you want to convert the range from 16-bit grayscale to the the range of uint8
.
Note: for converting the range from [0, 2^16-1] to [0, 255] you need to divide by (2**16-1)/255
= 257.0
. But this is not the main issue.
The main issue is converting the type to float
.
The valid range of float
images in OpenCV is [0, 1].
All values above 1.0
are white pixels, and 0.5
is a gray pixel.
You can keep the image type uint16
- you don't have to convert it to uint8
.
A white text color for uint16
type is 2**16-1
= 65535
(not 255).
Here is code sample that works with 16-bit grayscale (and uint16
type):
import numpy as np
import cv2
im = np.full((80, 80), 10000, np.uint16) # 16 bits grayscale synthetic image - set all pixels to 10000
cv2.circle(im, (40, 40), 10, 0, 20, cv2.LINE_8) # draw black cicle - synthetic image
#image = im[0]/255.0 #where im is just an np array of images (which are 80x80 np arrays)
image = im #where im is just an np array of images (which are 80x80 np arrays)
color = 2**16-1 # 65535 is white color for 16 bis image
# Using cv2.putText() method
image = cv2.putText(image, 'Out:16', (40, 15), cv2.FONT_HERSHEY_SIMPLEX, 0.3, color, 1, cv2.LINE_AA)
# Displaying the image
cv2.imshow("image", image)
cv2.waitKey()
The above code creates synthetic 16-bit grayscale for testing.
Converting from 16-bit grayscale to 8-bit grayscale:
# https://stackoverflow.com/questions/11337499/how-to-convert-an-image-from-np-uint16-to-np-uint8
uint8_image = cv2.convertScaleAbs(image, alpha=255.0/(2**16-1)) # Convent uint16 image to uint8 image (2**16-1 scaled to 255)
The above conversion assumes image
is full range 16 bits (pixel range [0, 65535]).
About the font:
OpenCV is computer vision oriented, and text drawing limited.
Why is the image black?
It's hard to answer without knowing the values of im[0]
.
im[0]
is not a 16-bit grayscale at all.im[0]
are very small.im[0]
is not uint16
.Drawing text using Pillow (PIL):
The quality of the small text is much better compared to OpenCV.
You can find for about quality text rendering here.
Continue with the uint8
image:
pil_image = Image.fromarray(uint8_image)
draw = ImageDraw.Draw(pil_image)
# specified font size
font = ImageFont.truetype('./arial.ttf', 10)
text = 'fyp:16'
# drawing text size
draw.text((5, 5), text, 255, font = font, align ="left")
pil_image.show()
Result:
I don't really know the reason your text looks wired compared to above result.
Upvotes: 1