【问题标题】:Writing text on a grayscale low resolution image在灰度低分辨率图像上书写文本
【发布时间】:2021-05-11 18:22:27
【问题描述】:

我一直在尝试将文本写入 80x80 16 位灰度图像,但在让它工作时遇到了一些问题。

我目前正在使用:

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) 

然而,文字不仅看起来很漂亮,而且占用了大量空间(我不能再往下看,否则它不清晰),除了文字是白色的,图像变得全黑。

是否有更好的方法将文本写入低分辨率图像(使文本更小)?为什么图像会变成全黑?

编辑:

我尝试使用 ImageDraw(),结果都是灰色的

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")

【问题讨论】:

  • 如果您的 OpenCV 构建是使用 Qt 作为 HighGUI 后端构建的,那么有使用 Qt 绘制文本的功能:docs.opencv.org/4.5.2/dc/d46/group__highgui__qt.html |否则请查看 PIL/Pillow 中的 ImageDrawImageFont。我在一个在 32x32 像素图标上添加小标签的脚本中使用它。
  • @DanMašek 检查我的编辑
  • 输入图像im[0]是什么?数据类型、值的范围,可能会附上一个可用于重现此的示例。此外,附上实际输出——这看起来像是使用 matplotlib 放大的可视化?

标签: python opencv


【解决方案1】:

看起来主要问题是将图像类型转换为float

假设(请验证):
im[0] 是 16 位灰度,im[0].dtypedtype('uint16')

image = im[0]/255.0 表示要将范围从 16 位灰度转换为uint8 的范围。
注意:要将范围从 [0, 2^16-1] 转换为 [0, 255],您需要除以 (2**16-1)/255 = 257.0。但这不是主要问题。

主要问题是将类型转换为float
OpenCV中float图像的有效范围是[0, 1]。
1.0 以上的所有值都是白色像素,0.5 是灰色像素。


您可以保留图像类型uint16 - 您不必将其转换为uint8
uint16 类型的白色文本颜色是 2**16-1 = 65535(不是 255)。

这是适用于 16 位灰度(和 uint16 类型)的代码示例:

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()

以上代码创建合成的 16 位灰度用于测试。


从 16 位灰度转换为 8 位灰度:

# 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)

上述转换假设image 是全范围16 位(像素范围[0, 65535])。


关于字体:
OpenCV 是面向计算机视觉的,文本绘制有限。


为什么图片是黑色的?

不知道im[0]的值很难回答。

  • 可能im[0] 根本不是 16 位灰度。
  • 可能是im[0] 的值非常小。
  • 可能im[0]的类型不是uint16

使用 Pillow (PIL) 绘制文本:

与OpenCV相比,小文本的质量要好得多。
你可以找到关于质量文本渲染的here

继续使用uint8 图像:

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()

结果:

与上述结果相比,我真的不知道您的文本看起来连线的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-23
    • 2013-11-29
    • 2016-02-17
    • 2014-11-20
    • 1970-01-01
    • 2018-12-02
    • 2011-04-07
    • 1970-01-01
    相关资源
    最近更新 更多