仿射变换实现

        处理仿射变换任务需获取两张图像的目标区域的三个坐标点((x11,y11),(x21,y21),(x31,y31)及(x12,y12),(x22,y22),(x32,y32)),三点确定一个平面,通过解6个方程获得6个参数。

        方程形式:

                x1=x2*a+y2*b+k1;

                y1=x2*c+y2*d+k2;

        通过opencv自带的 cv2.getAffineTransform()函数获得参数矩阵M,以及函数cv2.warpAffine()获得仿射变换后的图像。

测试

ptsa.jpg

ptsb.jpg

 res.jpg

        实现将ptsa两个三角形颜色替换为ptsb的颜色,保持ptsa的形状不变。在不获取ptsb的颜色的情况下,用仿射变换将ptsb中的形状直接变为ptsa,再将变换后的ptsb中的各坐标与ptsa对应并替换即可。

处理方法有2种:

1、将三角区域外接矩形放缩到同等大小,经过仿射变换后的图像目标区域可以直接替换到原图。

2、不进行放缩,直接仿射变换获得参数矩阵M(a,b,k1,c,d,k2),需要对目标区域所有坐标经M进行映射变换(上述方程)到原图。

方法一实现代码:

import cv2
import numpy as np

imga=cv2.imread('img/pica.jpg')
imgb=cv2.imread('img/picb.jpg')

ptsa=np.float32([[100,200],[250,100],[300,250]])#ptsa的左边三角区域三点坐标
ptsb=np.float32([[50,120],[150,50],[120,130]])#ptsb的左边三角区域三点坐标

ptsa_=np.float32([[250,100],[300,250],[400,150]])#ptsa的右边三角区域三点坐标
ptsb_=np.float32([[150,50],[120,130],[220,80]])#ptsb的右边三角区域三点坐标

# np.float32([[0,70*rh],[100*rw,0],[70*rw,80*rh]])

def IsTrangleOrArea(x1, y1, x2, y2, x3, y3):
    return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0)


def IsInside(x1, y1, x2, y2, x3, y3, x, y):
    # 三角形ABC的面积
    ABC = IsTrangleOrArea(x1, y1, x2, y2, x3, y3)

    # 三角形PBC的面积
    PBC = IsTrangleOrArea(x, y, x2, y2, x3, y3)

    # 三角形ABC的面积
    PAC = IsTrangleOrArea(x1, y1, x, y, x3, y3)

    # 三角形ABC的面积
    PAB = IsTrangleOrArea(x1, y1, x2, y2, x, y)

    return (ABC == PBC + PAC + PAB)


def warpTriangle(ptsa,ptsb,imga,imgb):
    r1=cv2.boundingRect(ptsa)
    r2=cv2.boundingRect(ptsb)
    roia=imga[r1[1]:r1[1]+r1[3],r1[0]:r1[0]+r1[2],:]
    roib=imgb[r2[1]:r2[1]+r2[3],r2[0]:r2[0]+r2[2],:]

    rate_h=roia.shape[0]/roib.shape[0]
    rate_w=roia.shape[1]/roib.shape[1]
    roib=cv2.resize(roib,(0,0),fx=rate_w,fy=rate_h)
    nptsa=[]
    nptsb=[]
    for i in range(3):
        nptsa.append([ptsa[i,0]-r1[0],ptsa[i,1]-r1[1]])
        nptsb.append([(ptsb[i, 0] - r2[0])*rate_w, (ptsb[i, 1] - r2[1])*rate_h])

    # print(ptsa)
    # print(ptsb)
    # print(nptsa)
    # print(nptsb)
    nptsa=np.array(nptsa,dtype=np.float32)
    nptsb=np.array(nptsb,dtype=np.float32)
    M=cv2.getAffineTransform(nptsb,nptsa)
    dst=cv2.warpAffine(roib,M,(roib.shape[1],roib.shape[0]))


    res=imga.copy()
    # print(ptsa[0,0], ptsa[0,1], ptsa[1,0], ptsa[1,1],ptsa[2,0], ptsa[2,1])
    print(r1[0],r1[0]+r1[2],r1[1], r1[1] + r1[3])
    for i in range(r1[1],r1[1]+r1[3]):
        for j in range(r1[0], r1[0] + r1[2]):
            if IsInside(ptsa[0,0], ptsa[0,1], ptsa[1,0], ptsa[1,1],ptsa[2,0], ptsa[2,1],j,i):
                res[i,j,:]=dst[i-r1[1],j-r1[0],:]

    return res


    # cv2.imshow('roia',roia)
    # cv2.imshow('dst',dst)


res=warpTriangle(ptsa,ptsb,imga,imgb)
res=warpTriangle(ptsa_,ptsb_,res,imgb)
cv2.imshow('res',res)
cv2.imshow('imgb',imgb)
cv2.imshow('imga', imga)
cv2.imwrite('res.jpg',res)
cv2.waitKey()

应用:

由于在处理图像过程中都是对矩形区域内像素进行遍历操作,而仿射变换需要3点坐标(即一个三角形),经变换后的图像部分区域不能直接替换到原图,而有效区域只是三角形内部,所以需要用到面积法进行有效区域的替换。如果处理的情况复杂,需要将目标区域拆分成多个三角区域(获取三点坐标)分别进行仿射变换。同时需要注意边界处理。

仿射变换原理参考:

何为仿射变换(Affine Transformation) - Alexander - 博客园

【OpenCV学习笔记】之仿射变换(Affine Transformation)_点滴成海~的博客-CSDN博客_仿射变换

图像的仿射变换原理及c++实现(旋转,平移,缩放,偏移,组合变换)_小武~~的博客-CSDN博客_c++仿射变换

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用 RANSAC 筛选和仿射变换实现图像间坐标对齐的 Python 代码示例: ```python import cv2 import numpy as np # 读取图像 img1 = cv2.imread('image1.jpg') img2 = cv2.imread('image2.jpg') # 将图像转换为灰度图像 gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # 初始化SIFT检测器 sift = cv2.xfeatures2d.SIFT_create() # 检测关键点和计算描述符 kp1, des1 = sift.detectAndCompute(gray1, None) kp2, des2 = sift.detectAndCompute(gray2, None) # 初始化暴力匹配器 bf = cv2.BFMatcher() # 匹配两幅图像的描述符 matches = bf.knnMatch(des1, des2, k=2) # 进行RANSAC筛选 good_matches = [] for m, n in matches: if m.distance < 0.75 * n.distance: good_matches.append(m) src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2) dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2) # 计算仿射变换矩阵 M, mask = cv2.estimateAffine2D(src_pts, dst_pts, method=cv2.RANSAC) # 将第一幅图像进行仿射变换 rows, cols = gray1.shape aligned = cv2.warpAffine(img1, M, (cols, rows)) # 拼接两幅图像 result = np.zeros((max(rows, rows), cols + cols, 3), dtype=np.uint8) result[:rows, :cols, :] = img2 result[:rows, cols:cols + cols, :] = aligned # 显示结果 cv2.imshow('Aligned Image', result) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在代码中,首先读取两幅待匹配的图像并将其转换为灰度图像,然后使用 SIFT 检测器检测关键点并计算描述符。接下来,使用暴力匹配器 `cv2.BFMatcher()` 对两幅图像的描述符进行匹配,并进行 RANSAC 筛选,得到匹配点对。然后,使用 `cv2.estimateAffine2D()` 函数计算仿射变换矩阵。最后,使用 `cv2.warpAffine()` 函数将第一幅图像进行仿射变换,并将两幅图像拼接在一起进行显示。 需要注意的是,`cv2.estimateAffine2D()` 函数可以选择使用 RANSAC 或者最小二乘法进行计算。在代码中,我们选择使用 RANSAC 筛选来提高算法的鲁棒性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HySmiley

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值