如何在OpenCV,Python中根据图像大小调整cv2.putText的文本大小?

hfsqlsce  于 2023-01-21  发布在  Python
关注(0)|答案(8)|浏览(1151)
fontScale = 1
fontThickness = 1

# make sure font thickness is an integer, if not, the OpenCV functions that use this may crash
fontThickness = int(fontThickness)

upperLeftTextOriginX = int(imageWidth * 0.05)
upperLeftTextOriginY = int(imageHeight * 0.05)

textSize, baseline = cv2.getTextSize(resultText, fontFace, fontScale, fontThickness)
textSizeWidth, textSizeHeight = textSize

# calculate the lower left origin of the text area based on the text area center, width, and height
lowerLeftTextOriginX = upperLeftTextOriginX
lowerLeftTextOriginY = upperLeftTextOriginY + textSizeHeight

# write the text on the image
cv2.putText(openCVImage, resultText, (lowerLeftTextOriginX, lowerLeftTextOriginY), fontFace, fontScale, Color,
            fontThickness)

看起来fontScale没有根据图像的宽度和高度来缩放文本,因为不同大小的图像中的文本几乎是相同的大小。那么我如何根据图像大小来调整文本的大小,以便所有的文本都能适合图像呢?

axr492tv

axr492tv1#

下面是一个将文本放入矩形的解决方案。如果矩形的宽度是可变的,那么你可以通过循环使用可能的缩放比例并测量文本的宽度(以像素为单位)来获得字体缩放比例。一旦你低于矩形宽度,你就可以检索缩放比例并使用它来实际putText

def get_optimal_font_scale(text, width):
    for scale in reversed(range(0, 60, 1)):
        textSize = cv.getTextSize(text, fontFace=cv.FONT_HERSHEY_DUPLEX, fontScale=scale/10, thickness=1)
        new_width = textSize[0][0]
        if (new_width <= width):
            print(new_width)
            return scale/10
    return 1
6jjcrrmo

6jjcrrmo2#

因为这起作用了!

scale = 1 # this value can be from 0 to 1 (0,1] to change the size of the text relative to the image
fontScale = min(imageWidth,imageHeight)/(25/scale)

请记住字体类型会影响常量25

qlckcl4x

qlckcl4x3#

方法

一种方法是将字体大小按比例缩放到图像大小。根据我的经验,不仅对fontScale应用此方法,而且对thickness应用此方法时,会获得更自然的结果。例如:

import math

import cv2

FONT_SCALE = 2e-3  # Adjust for larger font size in all images
THICKNESS_SCALE = 1e-3  # Adjust for larger thickness in all images

img = cv2.imread("...")
height, width, _ = img.shape

font_scale = min(width, height) * FONT_SCALE
thickness = math.ceil(min(width, height) * THICKNESS_SCALE)
示例

让我们以this free-to-use stock photo为例,我们通过将宽度重新调整为2000px和600px(保持纵横比不变)来创建两个版本的基础图像,使用上述方法,文本在两种情况下看起来都与图像大小相符(这里显示了一个示例性用例,我们在其中标注了边界框):

    • 2000像素**

    • 600像素**

    • 完整代码可供复制(* 但请注意:必须对输入图像进行预处理 ):*
import math

import cv2

FONT_SCALE = 2e-3  # Adjust for larger font size in all images
THICKNESS_SCALE = 1e-3  # Adjust for larger thickness in all images
TEXT_Y_OFFSET_SCALE = 1e-2  # Adjust for larger Y-offset of text and bounding box

img_width_to_bboxes = {
    2000: [
        {"xywh": [120, 400, 1200, 510], "label": "car"},
        {"xywh": [1080, 420, 790, 340], "label": "car"},
    ],
    600: [
        {"xywh": [35, 120, 360, 155], "label": "car"},
        {"xywh": [325, 130, 235, 95], "label": "car"},
    ],
}

def add_bbox_and_text() -> None:
    for img_width, bboxes in img_width_to_bboxes.items():
        # Base image from https://www.pexels.com/photo/black-suv-beside-grey-auv-crossing-the-pedestrian-line-during-daytime-125514/
        # Two rescaled versions of the base image created with width of 600px and 2000px
        img = cv2.imread(f"pexels-kaique-rocha-125514_{img_width}.jpg")
        height, width, _ = img.shape
        for bbox in bboxes:
            x, y, w, h = bbox["xywh"]
            cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
            cv2.putText(
                img,
                bbox["label"],
                (x, y - int(height * TEXT_Y_OFFSET_SCALE)),
                fontFace=cv2.FONT_HERSHEY_TRIPLEX,
                fontScale=min(width, height) * FONT_SCALE,
                thickness=math.ceil(min(width, height) * THICKNESS_SCALE),
                color=(0, 255, 0),
            )
        cv2.imwrite(f"pexels-kaique-rocha-125514_{img_width}_with_text.jpg", img)

if __name__ == "__main__":
    add_bbox_and_text()
x8diyxa7

x8diyxa74#

如果您对大小大约为1000 x 1000的图像使用fontScale = 1,那么这段代码应该可以正确地缩放字体。

fontScale = (imageWidth * imageHeight) / (1000 * 1000) # Would work best for almost square images

如果你仍然有任何问题,请发表评论。

wrrgggsh

wrrgggsh5#

我实现了一个函数来查找文本的最佳居中位置。

看看这些代码是否对您有所帮助。

def findFontLocate(s_txt, font_face, font_thick, cv_bgd):
    best_scale = 1.0
    bgd_w = cv_bgd.shape[1]
    bgd_h = cv_bgd.shape[0]
    txt_rect_w = 0
    txt_rect_h = 0
    baseline = 0
    for scale in np.arange(1.0, 6.0, 0.2):
        (ret_w, ret_h), tmp_bsl = cv2.getTextSize(
            s_txt, font_face, scale, font_thick)
        tmp_w = ret_w + 2 * font_thick
        tmp_h = ret_h + 2 * font_thick + tmp_bsl
        if tmp_w >= bgd_w or tmp_h >= bgd_h:
            break
        else:
            baseline = tmp_bsl
            txt_rect_w = tmp_w
            txt_rect_h = tmp_h
            best_scale = scale
    lt_x, lt_y = round(bgd_w/2-txt_rect_w/2), round(bgd_h/2-txt_rect_h/2)
    rb_x, rb_y = round(bgd_w/2+txt_rect_w/2), round(bgd_h/2+txt_rect_h/2)-baseline
    return (lt_x, lt_y, rb_x, rb_y), best_scale, baseline

注意,该函数接受四个参数:s_txt(要渲染的字符串)、font_facefont_thickcv_bgd(ndarray格式的背景图像)
putText()时,编写如下代码:

cv2.putText(
    cv_bgd, s_txt, (lt_x, rb_y), font_face,
    best_scale, (0,0,0), font_thick, cv2.LINE_AA)
tv6aics1

tv6aics16#

您可以使用get_optimal_font_scale函数,如下所示,根据图像大小调整字体大小:

def get_optimal_font_scale(text, width):

    for scale in reversed(range(0, 60, 1)):
        textSize = cv2.getTextSize(text, fontFace=cv2.FONT_HERSHEY_DUPLEX, fontScale=scale/10, thickness=1)
        new_width = textSize[0][0]
        if (new_width <= width):
            return scale/10
    return 1

fontScale = 3*(img.shape[1]//6)
font_size = get_optimal_font_scale(text, fontScale)
cv2.putText(img, text, org, font, font_size, color, thickness, cv2.LINE_AA)

您可以更改映像的fontScale

n9vozmp4

n9vozmp47#

这是我的工作。

double calc_scale_rectbox(const char *txt, int box_width, int box_height, 
                          cv::Size &textSize, int &baseline)

{
       if (!txt) return 1.0;
       double scale = 2.0;
       double w_aprx = 0;
       double h_aprx = 0;
       do
       {
           textSize = cv::getTextSize(txt, FONT_HERSHEY_DUPLEX, scale, 2, 
                                      &baseline);
           w_aprx = textSize.width * 100 / box_width;
           h_aprx = textSize.height * 100 / box_height;
           scale -= 0.1;
        } while (w_aprx > 50 || h_aprx > 50);
        return scale;
 }

......

cv::Size textSize;

int baseline = 0;

double scale = calc_scale_rectbox(win_caption.c_str(), width, 
                                 height, textSize, baseline);

cv::putText(img, win_caption, Point(width / 2 - textSize.width / 2, 
           (height + textSize.height - baseline + 2) / 2), 
            FONT_HERSHEY_DUPLEX, scale, CV_RGB(255, 255, 255), 2);
2o7dmzc5

2o7dmzc58#

一个简单的效用函数:

def optimal_font_dims(img, font_scale = 2e-3, thickness_scale = 5e-3):
    h, w, _ = img.shape
    font_scale = min(w, h) * font_scale
    thickness = math.ceil(min(w, h) * thickness_scale)
    return font_scale, thickness

用法:

font_scale, thickness = optimal_font_dims(image)
cv2.putText(image, "LABEL", (x, y), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (255,0,0), thickness)

相关问题