在脸周围画出华丽的矩形

11

我正在使用以下代码来检测人脸并在脸部上方绘制矩形框:

while True:
    # get video frame
    ret, img = cap.read()

    input_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img_h, img_w, _ = np.shape(input_img)

    detected = detector(input_img, 1)

    for i, d in enumerate(detected):
        x1, y1, x2, y2, w, h = d.left(), d.top(), d.right() + 1, d.bottom() + 1, d.width(), d.height()
        cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 0), 2)

    cv2.imshow("result", img)
    key = cv2.waitKey(30)

    if key == 27:
        break

这个矩形看起来像这样:

但我想要一个类似于这个的矩形:

是否有任何OpenCV或dlib函数可以帮助我获得这种有效的矩形?


有各种绘图函数可让您绘制线条弧形。看起来这就是您想要实现的一切所需。 - Dan Mašek
2
哎呀,页面找不到了。 - Trect
1
@DheerajMPai 很好的发现。我设法找到了这些图片(幸运的是路径只有轻微的变化),并将它们本地上传,所以在未来应该会很好。谢谢(还有感谢赏金 :) ) - Dan Mašek
4个回答

16

使用绘制线段椭圆弧的函数,可以实现您想要的效果。

您想要绘制的框架由4个相似部分组成(每个角落一个),每个部分都旋转(或镜像)。

让我们看看左上角:

Illustration

正如您所看到的,我们需要绘制2条长度为d的线段和一段弧(半径为r的1/4圆)。

假设左上角的坐标是(x1, y1)

那么,弧的中心将位于位置(x1 + r, y1 + r)

其中一条线段将从(x1 + r, y1)延伸到(x1 + r + d, y1)

另一条线段将从(x1, y1 + r)延伸到(x1, y1 + r + d)

其他角落也会发生类似的情况。


示例代码:

import cv2
import numpy as np

# ============================================================================

def draw_border(img, pt1, pt2, color, thickness, r, d):
    x1,y1 = pt1
    x2,y2 = pt2

    # Top left
    cv2.line(img, (x1 + r, y1), (x1 + r + d, y1), color, thickness)
    cv2.line(img, (x1, y1 + r), (x1, y1 + r + d), color, thickness)
    cv2.ellipse(img, (x1 + r, y1 + r), (r, r), 180, 0, 90, color, thickness)

    # Top right
    cv2.line(img, (x2 - r, y1), (x2 - r - d, y1), color, thickness)
    cv2.line(img, (x2, y1 + r), (x2, y1 + r + d), color, thickness)
    cv2.ellipse(img, (x2 - r, y1 + r), (r, r), 270, 0, 90, color, thickness)

    # Bottom left
    cv2.line(img, (x1 + r, y2), (x1 + r + d, y2), color, thickness)
    cv2.line(img, (x1, y2 - r), (x1, y2 - r - d), color, thickness)
    cv2.ellipse(img, (x1 + r, y2 - r), (r, r), 90, 0, 90, color, thickness)

    # Bottom right
    cv2.line(img, (x2 - r, y2), (x2 - r - d, y2), color, thickness)
    cv2.line(img, (x2, y2 - r), (x2, y2 - r - d), color, thickness)
    cv2.ellipse(img, (x2 - r, y2 - r), (r, r), 0, 0, 90, color, thickness)

# ============================================================================

img = np.zeros((256,256,3), dtype=np.uint8)

draw_border(img, (10,10), (100, 100), (127,255,255), 1, 10, 20)
draw_border(img, (128,128), (240, 160), (255,255,127), 1, 5, 5)

cv2.imwrite('round_rect.png', img)

结果:

结果


1
你是一个超级天才! - user6038900
1
太棒了!!这真的非常有帮助!我太无聊了,看那愚蠢的绿色矩形输出。 - Trect
如果我有更多的声望,我会把它们全部作为赏金奖励。 - Trect

3
我做了一些天真的事情。您可以使用一个函数进行进一步修改来实现。
步骤:
1. 我手动标记了文本周围的矩形,并提取了4个点。 2. 然后,我为从这4个点绘制的线条固定了一个长度。
结果:

enter image description here

使用的函数:

  • cv2.line()
  • cv2.rectangle()

请查看此链接以了解有关其使用的详细信息。


你上面的答案非常棒。也许你可以进行编辑。 - Trect
不要只添加链接,而是添加整个代码的内容。 - Trect

1

不要寻找一个可以制作花哨矩形的函数/库,以下策略可能更容易:

步骤1 - 下载所需矩形的图像,该图像应仅包含四个角落的4个线条,其余背景应为黑色

步骤2 - 在您的代码中,使用imread将此图像保存为Mat对象:

border = cv2.imread('your_img.jpg')

步骤3 - 修改您的for循环以在检测到的矩形上叠加border Mat,如下所示:

for i, d in enumerate(detected):
    x1, y1, x2, y2, w, h = d.left(), d.top(), d.right() + 1, d.bottom() + 1, d.width(), d.height()

    #cv2.rectangle won't be needed anymore
    #cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 0), 2)

    roi=img[y1+h/2-100:y1+h/2+100,x1+w/2-100:x1+w/2+100]
    #this points to a section in original image
    cv2.addWeighted(roi,1,border,1,0,roi)

请确保roiborder的大小相同,否则您的代码将崩溃。
这将在您的输入帧上叠加角落笔画,并忽略黑色背景。

0

Drawing Fancy Rectangle

感谢@Dan Mašek的建议。您可以通过以下方式轻松绘制漂亮的矩形。您可以在此处查看完整详情:绘制漂亮的圆角矩形
def draw_border(img, pt1, pt2, color, thickness, r, d):
    x1,y1 = pt1
    x2,y2 = pt2

    # Top left
    cv2.line(img, (x1 + r, y1), (x1 + r + d, y1), color, thickness)
    cv2.line(img, (x1, y1 + r), (x1, y1 + r + d), color, thickness)
    cv2.ellipse(img, (x1 + r, y1 + r), (r, r), 180, 0, 90, color, thickness)

    # Top right
    cv2.line(img, (x2 - r, y1), (x2 - r - d, y1), color, thickness)
    cv2.line(img, (x2, y1 + r), (x2, y1 + r + d), color, thickness)
    cv2.ellipse(img, (x2 - r, y1 + r), (r, r), 270, 0, 90, color, thickness)

    # Bottom left
    cv2.line(img, (x1 + r, y2), (x1 + r + d, y2), color, thickness)
    cv2.line(img, (x1, y2 - r), (x1, y2 - r - d), color, thickness)
    cv2.ellipse(img, (x1 + r, y2 - r), (r, r), 90, 0, 90, color, thickness)

    # Bottom right
    cv2.line(img, (x2 - r, y2), (x2 - r - d, y2), color, thickness)
    cv2.line(img, (x2, y2 - r), (x2, y2 - r - d), color, thickness)
    cv2.ellipse(img, (x2 - r, y2 - r), (r, r), 0, 0, 90, color, thickness)


def detect(path,img):
    cascade = cv2.CascadeClassifier(path)

    img=cv2.imread(img,1)
    # converting to gray image for faster video processing
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    rects = cascade.detectMultiScale(gray, 1.2, 3,minSize=(50, 50))
    # if at least 1 face detected
    if len(rects) >= 0:
        # Draw a rectangle around the faces
        for (x, y, w, h) in rects:
            draw_border(img, (x, y), (x + w, y + h), (255, 0, 105),4, 15, 10)
        # Display the resulting frame
        cv2.imshow('Face Detection', img)
        # wait for 'c' to close the application
        cv2.waitKey(0)

你刚才只是复制粘贴了第一个答案,不管怎样还是谢谢。 - user6038900
这就是为什么我也感谢他的代码。我认为你没有正确阅读我的评论。请仔细检查,我尝试使用人脸检测和花式矩形回答问题。 - Md. Hanif Ali Sohag

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接