2D图像像素点操作——平移,旋转,缩放 tcy

1.1.用途:
    平移(Translation)、缩放(Scale)、翻转(Flip)、旋转(Rotation)和剪切(Shear)

2.1.平移
说明:
    点(x,y)向x方向移动dx, y方向移动dy 
变换后坐标:
    (x',y')=(x+dx,y+dy)
矩阵表示:   
    [x',y',1]=[1 0 dx][0 1 dy] [0 0 1]*[[x],[y],[1]]
2.2.缩放
说明:
    设点(x,y)在x轴方向扩大sx倍,y轴方向扩大sy倍
变换后坐标:
    (x',y')=(sx * x,sy * y)
矩阵表示:   
    [x',y',1]=[[sx 0 0] [0 sy 0][0 0 1]]  *[[x],[y],[1]]#缩放矩阵
2.3.旋转
说明:
    设点A(x1,y1)以原点(x0,y0)为圆心旋转θ度,求旋转后 A'(x',y')坐标值.
变换后坐标:
    y = rows-y
    x' = x0 + (x1 - x0) cosθ - (y1 - y0)sinθ
    y' = y0 +(y1 - y0)cosθ + (x1 - x0) sinθ
    y' = rows-y'

变换后坐标(x',y'):
    x=rcos(b);y=rsin(b);
    x'=rcos(a+b)=rcosacosb−rsinasinb=xcosa−ysina;(合角公式)
    y'=rsin(a+b)=rsinacosb+rcosasinb=xsina+ycosa;

旋转变换矩阵:
    [[cosa −sina][sina cosa]]#逆时针
2.4。翻转
    [x',y',1]=[ [1 0 0 ][0 -1 N+1][0 0 1] ]*[x,y,1]
    
=============================================================================================
2.5.等距变换
R=[
    [r11 r12 dx]#平移变换和旋转变换的复合;等距变换前后长度,面积,线段之间的夹角都不变
    [r21 r22 dy]#左上角2×2矩阵为旋转部分,tx和ty为平移因子
    [0   0   1 ]#有三自由度,即旋转,x方向平移,y方向平移。
]

=============================================================================================
2.6.切向变换 
相当于一个横向截切与一个纵向剪切的复合常用于产生弹性物体的变形处理
[
    [ 1   shx 0]
    [shy  1   0]
    [ 0   0   1]
]
#https://www.cnblogs.com/liekkas0626/p/5238564.html
=============================================================================================
2.7.相似变换
    相似变换相当于是等距变换和均匀缩放的一个复合
    相似变换前后长度比,夹角,虚圆点I,J保持不变。相似变换其实与相似三角形之间是有类似的
S=[
    [s*r11 s*r12 dx]#左上角2×2矩阵为旋转部分,dx和dy为平移因子
    [s*r21 s*r22 dy]#有4个自由度,即旋转,x方向平移,y方向平移和缩放因子s
    [  0    0    1 ]
]

=============================================================================================
2.8.仿射变换
性质:
    1)保持二维图形“平直性”和“平行性”,面积比保持不变;
    2)不具有保角性和保持距离比的性质不能保持垂直性角度会改变
       共线线段或者平行线段的长度比保持不变,矢量的线性组合不变
    3)有6自由度,即旋转4个,也就是前述大矩形的4个元素都可以同时改变,x方向平移,y方向平移。
       包括平移、旋转、缩放、倾斜(错切、剪切、偏移)、翻转变换 
说明:   
    平直性:变换后直线还是直线、圆弧还是圆弧。
    平行性:平行线还是平行线,直线上点的位置顺序不变
计算:
    [u,v,1]=[[a1 b1  c1] [a2 b2 c2 ][0 0 1]]*[x,y,1]

 

3.投影变换(透视变换,射影变换)

3.1.射影变换:
    是最一般的线性变换。有8个自由度。
    射影变换保持重合关系和交比不变。但不会保持平行性。即它会使得仿射变换产生非线性效应。

3.2.射影变换仿射变换区别:
    射影变换变换矩阵[[a11 a12  a13] [a21 a22  a23 ][a31 a32  a33]]
    仿射变换变换矩阵[[a11 a12  a13] [a21 a22  a23 ][0 0 1]]

    在仿射的前提下,当左上角2×2矩阵正交时为欧式变换,左上角矩阵行列式为1时为定向欧式变换。
    所以射影变换包含仿射变换,而仿射变换包含欧式变换。

    [a11 a12 ] [a21 a22 ]表示线性变换如scaling(尺度),shearing(剪切)和ratotion(旋转)
    [a13 a23]表示平移参数,一个确定在x方向上的平移一个确定在y方向上的平移;
    [a31 a32]用于产生透视变换。从这里所以可以理解成仿射等是透视变换的特殊形式

名词解释:
    projective transformation(投影变换) = homography(单应性变换) = collineation( 直射变换)
    
=============================================================================================
4.备注最终变换矩阵
    2D基本模型视图变换只有上面这3种
    如某变换先经过平移(对应平移矩阵A)再旋转(对应旋转矩阵B)再缩放(对应缩放矩阵C)
    最终变换矩阵 T = ABC. #即3个矩阵按变换先后顺序依次相乘(矩阵乘法不满足交换律,讲究先后顺序)
    
5.实例:
旋转矩阵方法没有实现,有高手请补充

# !/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import cv2,math

class Pixel():
    def __int__(self):pass 
    def __del__(self): pass
    
    def movePixelPoint(self,x,y,dx=0,dy=0)->list:
        b = [[1, 0, dx], [0, 1, dy], [0, 0, 1]]#平移矩阵
        X = [[x], [y], [1]]
        R=np.dot(b, X)           # X'=bX
        R=R.reshape(3)[0:2]
    
        return R.tolist()

    def zoomPixelPoint(self,x,y,sx=1,sy=1)->list:
        b = np.array([[sx, 0, 0], [0, sy, 0], [0, 0, 1]],dtype=np.float)#缩放矩阵
        X = np.array([[x], [y], [1]],dtype=np.float)
        R = np.dot(b, X)  # X'=bX
        R = np.uint8(R.round())
        R = R.reshape(3)[0:2]
    
        return R.tolist()

    def rotatePixelPoint(self,x,y,θ:int=0.0,center=(0.0,0.0),rows=480)->list:
        cosθ=math.cos(math.radians(θ))
        sinθ = math.sin(math.radians(θ))
        x1 = x
    
        y1 = rows - y
        x0 = center[0]
        y0 = rows - center[1]
        x = (x1-x0)*cosθ - (y1 - y0)*sinθ + x0
        y = (x1-x0)*sinθ + (y1 - y0)*cosθ + y0
        x=x
        y = rows - y
    
        return x,y

    def rotatePixelPoint_(self,x,y,angle:int=0.0,center=(0.0,0.0))->list:
        scale=1
        x0, y0 = center

        cosθ = math.cos(math.radians(angle))
        sinθ = math.sin(math.radians(angle))
        α ,β= scale*cosθ,scale*sinθ

        # b = [[  α,β,(1- α)*x0 - β*y0],[ -β,α,β*x0+(1 - α)*y0],[0, 0, 1]]
        b =[[cosθ ,- sinθ,(1 - cosθ)*x0 + y0 * sinθ],[sinθ ,   cosθ,(1 - cosθ)*y0 - x0 * sinθ], [0 ,  0  , 1]]
        X = [[x], [y], [1]]

        R = np.dot(b, X)
        R = np.uint8(R.round())
        R = R.reshape(3)[0:2]
        R=R.tolist()
        return R
    
    #====================================================================================
    def __move__(self,src, pos: '(int,int)') -> np.ndarray:      # 彩色平移
        rows, cols = src.shape[:2]
        M = np.float32([[1, 0, pos[0]], [0, 1, pos[1]]])  # 平移转换矩阵: 右移动100;下移动50
        dst = cv2.warpAffine(src, M, (cols, rows))    # 图像的宽度和高度
        return dst

    def __rotation_Scale__(self,src, angle:'float',rotation_center:'(float,float)'=None,scale:'float'=1)->np.ndarray:#彩色:旋转缩放
        rows, cols = src.shape[:2]
        cx=rotation_center[0] if rotation_center else cols/2.0
        cy=rotation_center[1] if rotation_center else rows/2.0
    
        # cols - 1 and rows - 1 are the coordinate limits.
        M = cv2.getRotationMatrix2D((cx, cy), angle, scale)
        dst = cv2.warpAffine(src, M, (int(2*cx), int(2*cy)))
    
        return dst

    def __polylines__(self,img,pts:'ndarray.int32', isClosed:'bool', color:'tuple',thickness=1,lineType=8)->np.ndarray:
        tmp=thickness
        if thickness<0:thickness=1
        cv2.__polylines__(img, pts, isClosed, color, thickness, lineType)# 绘图多边形(pts多边形各定点int32, Isclosed是否封闭)
        if tmp<0: cv2.fillPoly(img, pts, color)
        return  img

    def __getColorPicture__(self):
        img = np.zeros((480, 640, 3), dtype=np.uint8)
        pts = np.array([[100, 50], [200, 300], [70, 200], [50, 100]], np.int32)
        pts = pts.reshape((-1, 1, 2))
        img = self.__polylines__(img, [pts], True, (125, 255, 0), -1)
    
        cv2.putText(img, 'A', (100, 50-10), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 1, 8)
        cv2.putText(img, 'B', (200, 300 + 10), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 1, 8)
        cv2.putText(img, 'C', (70-20, 200+10), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255), 1, 8)
    
        return img

    def __getColorPictureInCenter__(self):
        rgb=self.__getColorPicture__()
        img,rect,box=self.__getContours__(rgb)

        # 移动到中心
        cx_rect, cy_rect = int(round(rect[0][0], 0)), int(round(rect[0][1], 0))
        cv2.drawMarker(rgb, (cx_rect, cy_rect), (0, 0, 255))

        h, w = int(round(rgb.shape[0] / 2, 0)), int(round(rgb.shape[1] / 2, 0))

        dx, dy = w - cx_rect, h - cy_rect
        rgb_center = self.__move__(rgb, (dx, dy))

        return rgb_center

    def __getContours__(self,rgb):
        img=rgb.copy()
        gray = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)
        
        # 寻找二值图像轮廓
        ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
        contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        cnt = contours[1]
        cv2.drawContours(img, [cnt], 0, (125, 125, 125), 2)
    
        # 获取最小外接矩形
        rect = cv2.minAreaRect(cnt)
        box = cv2.boxPoints(rect)
        box = np.int0(box.round())
        cv2.drawContours(img, [box], 0, (0, 255, 255), 2)
        
        return img,rect,box


    def test_movePixelPoint(self,dx=50,dy=50):
        rgb=self.__getColorPictureInCenter__()
        img1,rect1,box1=self.__getContours__(rgb)

        img_ = self.__move__(rgb, (dx, dy))
        img2, rect2,box2 = self.__getContours__(img_)

        for i in range(4):
            x1,y1=box1[i]
            x2,y2=box2[i]
            x,y=self.movePixelPoint(x1,y1,dx,dy)
            x_,y_=x1+dx,y1+dy
            print('[%s  %s %s %s ] [(x,y)=%s;(x1,y1)=%s;(x2,y2)=%s;]'%((x2-x1==dx),(y2-y1==dy),x2-x1-dx,y2-y1-dy,(x,y),(x1,y1),(x2,y2)))

        cv2.imshow('s1', img1)
        cv2.imshow('s2', img2)
        cv2.waitKey()

    def test_zoomPixelPoint(self,fx=0.5, fy=0.5):
        rgb = self.__getColorPictureInCenter__()
        img1, rect1, box1 = self.__getContours__(rgb)

        img_ = cv2.resize(rgb,None,fx=fx, fy=fy, interpolation = cv2.INTER_CUBIC)
        img2, rect2, box2 = self.__getContours__(img_)

        for i in range(4):
            x1, y1 = box1[i]
            x2, y2 = box2[i]
            x,y=self.zoomPixelPoint(x1, y1, sx=fx, sy=fy)

            print('[%s  %s %s %s ] [(x,y)=%s;(x1,y1)=%s;(x2,y2)=%s;]' % ((x2 - x == 0), (y2 - y == 0), x2 - x , y2 - y, (x, y), (x1, y1), (x2, y2)))

        cv2.imshow('s1', img1)
        cv2.imshow('s2', img2)
        cv2.waitKey()

    def test_rotatePixelPoint(self):
        rotateangle = -180
        center = (320, 240)

        rgb = self.__getColorPictureInCenter__()
        img1, rect1, box1 = self.__getContours__(rgb)

        img_ = self.__rotation_Scale__(rgb, angle=rotateangle,rotation_center=center,scale=1)
        img2, rect2, box2 = self.__getContours__(img_)

        for i in range(4):
            x1,y1=box1[i]
            x2, y2 = box2[i]
            x,y=self.rotatePixelPoint(x1, y1, rotateangle, center)
            print('[%s  %s %s %s ] [(x,y)=%s;(x1,y1)=%s;(x2,y2)=%s;]' % (
            (x2 - x == 0), (y2 - y == 0), x2 - x, y2 - y, (x, y), (x1, y1), (x2, y2)))

        cv2.imshow('s1', img1)
        cv2.imshow('s2', img2)
        cv2.waitKey()

if  __name__ =='__main__':
    a=Pixel()
    # a.test_movePixelPoint(dx=150,dy=50)
    """
    [True  True 0 0 ] [(x,y)=(481, 432);(x1,y1)=(331, 382);(x2,y2)=(481, 432);]
    [True  True 0 0 ] [(x,y)=(380, 181);(x1,y1)=(230, 131);(x2,y2)=(380, 181);]
    [True  True 0 0 ] [(x,y)=(460, 149);(x1,y1)=(310, 99);(x2,y2)=(460, 149);]
    [True  True 0 0 ] [(x,y)=(561, 400);(x1,y1)=(411, 350);(x2,y2)=(561, 400);]
    """
    # a.test_zoomPixelPoint()
    """
    [False  True -1 0 ] [(x,y)=(166, 191);(x1,y1)=(331, 382);(x2,y2)=(165, 191);]
    [True  False 0 -1 ] [(x,y)=(115, 66);(x1,y1)=(230, 131);(x2,y2)=(115, 65);]
    [True  False 0 -1 ] [(x,y)=(155, 50);(x1,y1)=(310, 99);(x2,y2)=(155, 49);]
    [False  False -1 -1 ] [(x,y)=(206, 175);(x1,y1)=(411, 350);(x2,y2)=(205, 174);]
    """
    a.test_rotatePixelPoint()
    """
    (x,y)=(309.0, 98.0)	(x1,y1)=(331, 382)	    C	(x2,y2)=(330, 381)  A
    (x,y)=(410.0, 349.0)	(x1,y1)=(230, 131)	D	(x2,y2)=(229, 130)	B
    (x,y)=(330.0, 381.0)	(x1,y1)=(310, 99)	A	(x2,y2)=(309, 98)	C
    (x,y)=(229.0, 130.0)	(x1,y1)=(411, 350)	B	(x2,y2)=(410, 349)	D
                               
    (x,y)=(330.0, 381.0)	(x1,y1)=(310, 99)	A	(x2,y2)=(330, 381)	A
    (x,y)=(229.0, 130.0)	(x1,y1)=(411, 350)	B	(x2,y2)=(229, 130)	B
    (x,y)=(309.0, 98.0)	(x1,y1)=(331, 382)	    C	(x2,y2)=(309, 98)	C
    (x,y)=(410.0, 349.0)	(x1,y1)=(230, 131)	D	(x2,y2)=(410, 349)	D

    """

 

 

 

 

你可能感兴趣的:(python)