为了账号安全,请及时绑定邮箱和手机立即绑定

如何在opencv中应用三点三角形渐变?

如何在opencv中应用三点三角形渐变?

哈士奇WWW 2022-11-24 15:03:32

假设我们有像这样的 Delaunay 三角剖分:

http://img1.sycdn.imooc.com/637f175a0001031702390240.jpg

产生fillConvexPolygetVoronoiFacetList

里面有三角形,可以通过 得到getTriangleList。我想绘制 Delaunay-triangulation,就像它是一个由三角形组成的平滑渐变图像,如下所示:

http://img2.sycdn.imooc.com/637f17630001a16603130187.jpg

如何在 opencv 中做这样的事情?



查看完整描述

3 回答

?
饮歌长啸

TA贡献1679条经验 获得超2个赞

我修改了@ fmw42的答案以利用向量计算(由 支持)并删除循环以获得更好的性能。np.linalg.lstsqfor


    #!/usr/bon/env python

    import cv2

    import numpy as np

    

    # create black background image

    result = np.zeros((500,500,3), dtype=np.uint8)

    

    # Specify (x,y) triangle vertices

    a = (250,100)

    b = (100,400)

    c = (400,400)

    

    # Specify colors

    red = np.array([0,0,255])

    green = np.array([0,255,0])

    blue = np.array([255,0,0])

    

    # Make array of vertices

    # ax bx cx

    # ay by cy

    #  1  1  1

    triArr = np.asarray([a[0],b[0],c[0], a[1],b[1],c[1], 1,1,1]).reshape((3, 3))

    

    # Get bounding box of the triangle

    xleft = min(a[0], b[0], c[0])

    xright = max(a[0], b[0], c[0])

    ytop = min(a[1], b[1], c[1])

    ybottom = max(a[1], b[1], c[1])

    

    # Build np arrays of coordinates of the bounding box

    xs = range(xleft, xright)

    ys = range(ytop, ybottom)

    xv, yv = np.meshgrid(xs, ys)

    xv = xv.flatten()

    yv = yv.flatten()

    

    # Compute all least-squares /

    p = np.array([xv, yv, [1] * len(xv)])

    alphas, betas, gammas = np.linalg.lstsq(triArr, p, rcond=-1)[0]

    

    # Apply mask for pixels within the triangle only

    mask = (alphas > 0) & (betas > 0) & (gammas > 0)

    alphas_m = alphas[mask]

    betas_m = betas[mask]

    gammas_m = gammas[mask]

    xv_m = xv[mask]

    yv_m = yv[mask]

    

    def mul(a, b) :

        # Multiply two vectors into a matrix

        return np.asmatrix(b).T @ np.asmatrix(a)

    

    # Compute and assign colors

    colors = mul(red, alphas_m) + mul(green, betas_m) + mul(blue, gammas_m)

    result[xv_m, yv_m] = colors

    

    # show results

    cv2.imshow('result', result)

    cv2.waitKey(0)

    cv2.destroyAllWindows()



查看完整回答
反对 回复 4天前
?
慕田峪4524236

TA贡献1592条经验 获得超5个赞

这是在 Python/OpenCV 中执行此操作的方法,但它会比我之前介绍的 Python/Wand 版本慢,因为它必须循环并在重心坐标的每个像素处求解线性最小二乘方程。


import cv2

import numpy as np


# References: 

# https://stackoverflow.com/questions/31442826/increasing-efficiency-of-barycentric-coordinate-calculation-in-python

# https://math.stackexchange.com/questions/81178/help-with-cramers-rule-and-barycentric-coordinates


# create black background image

result = np.zeros((500,500,3), dtype=np.uint8)


# Specify (x,y) triangle vertices

a = (250,100)

b = (100,400)

c = (400,400)


# Specify colors

red = (0,0,255)

green = (0,255,0)

blue = (255,0,0)


# Make array of vertices

# ax bx cx

# ay by cy

#  1  1  1

triArr = np.asarray([a[0],b[0],c[0], a[1],b[1],c[1], 1,1,1]).reshape((3, 3))


# Get bounding box of the triangle

xleft = min(a[0], b[0], c[0])

xright = max(a[0], b[0], c[0])

ytop = min(a[1], b[1], c[1])

ybottom = max(a[1], b[1], c[1])


# loop over each pixel, compute barycentric coordinates and interpolate vertex colors

for y in range(ytop, ybottom):


    for x in range(xleft, xright):


        # Store the current point as a matrix

        p = np.array([[x], [y], [1]])


        # Solve for least squares solution to get barycentric coordinates

        (alpha, beta, gamma) = np.linalg.lstsq(triArr, p, rcond=-1)[0]


        # The point is inside the triangle if all the following conditions are met; otherwise outside the triangle

        if alpha > 0 and beta > 0 and gamma > 0:

            # do barycentric interpolation on colors

            color = (red*alpha + green*beta + blue*gamma)

            result[y,x] = color


# show results

cv2.imshow('result', result)

cv2.waitKey(0)

cv2.destroyAllWindows()


# save results

cv2.imwrite('barycentric_triange.png', result)


结果:

//img1.sycdn.imooc.com/637f17890001cfbe04880489.jpg

查看完整回答
反对 回复 4天前
?
白板的微信

TA贡献1586条经验 获得超3个赞

在 OpenCV 中,我认为没有任何现成的函数可以做到这一点。您将不得不遍历图像中的每个像素并计算重心(区域)插值。参见例如https://codeplea.com/triangular-interpolation


但是,在 Python/Wand(基于 ImageMagick)中,您可以按如下方式进行:


import numpy as np

from wand.image import Image

from wand.color import Color

from wand.drawing import Drawing

from wand.display import display


# define vertices of triangle

p1 = (250, 100)

p2 = (100, 400)

p3 = (400, 400)


# define barycentric colors and vertices

colors = {

    Color('RED'): p1,

    Color('GREEN1'): p2,

    Color('BLUE'): p3

}


# create black image

black = np.zeros([500, 500, 3], dtype=np.uint8)


with Image.from_array(black) as img:

    with img.clone() as mask:

        with Drawing() as draw:

            points = [p1, p2, p3]

            draw.fill_color = Color('white')

            draw.polygon(points)

            draw.draw(mask)

            img.sparse_color('barycentric', colors)

            img.composite_channel('all_channels', mask, 'multiply', 0, 0)   

            img.format = 'png'

            img.save(filename='barycentric_image.png')

            display(img)


结果:

//img1.sycdn.imooc.com/637f17b20001cae404820484.jpg

查看完整回答
反对 回复 4天前

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信