Opencv-Python 图像透视变换cv2.warpPerspective

# -*- coding:utf-8 -*-
import cv2
import numpy as np
import sys
 
img = cv2.imread("test.jpg")
#cv2.namedWindow('original',2)
#cv2.imshow("original", img)
 
# 可选,扩展图像,保证内容不超出可视范围
img = cv2.copyMakeBorder(img, 200, 200, 200, 200, cv2.BORDER_CONSTANT, 0)
w, h = img.shape[0:2]
 
anglex = 0
angley = 30
anglez = 0  # 是旋转
fov = 42
r = 0
 
def rad(x):
    return x * np.pi / 180
 
def get_warpR():
    global anglex,angley,anglez,fov,w,h,r
    # 镜头与图像间的距离,21为半可视角,算z的距离是为了保证在此可视角度下恰好显示整幅图像
    z = np.sqrt(w ** 2 + h ** 2) / 2 / np.tan(rad(fov / 2))
    # 齐次变换矩阵
    rx = np.array([[1, 0, 0, 0],
                   [0, np.cos(rad(anglex)), -np.sin(rad(anglex)), 0],
                   [0, -np.sin(rad(anglex)), np.cos(rad(anglex)), 0, ],
                   [0, 0, 0, 1]], np.float32)
 
    ry = np.array([[np.cos(rad(angley)), 0, np.sin(rad(angley)), 0],
                   [0, 1, 0, 0],
                   [-np.sin(rad(angley)), 0, np.cos(rad(angley)), 0, ],
                   [0, 0, 0, 1]], np.float32)
 
    rz = np.array([[np.cos(rad(anglez)), np.sin(rad(anglez)), 0, 0],
                   [-np.sin(rad(anglez)), np.cos(rad(anglez)), 0, 0],
                   [0, 0, 1, 0],
                   [0, 0, 0, 1]], np.float32)
 
    r = rx.dot(ry).dot(rz)
 
    # 四对点的生成
    pcenter = np.array([h / 2, w / 2, 0, 0], np.float32)
 
    p1 = np.array([0, 0, 0, 0], np.float32) - pcenter
    p2 = np.array([w, 0, 0, 0], np.float32) - pcenter
    p3 = np.array([0, h, 0, 0], np.float32) - pcenter
    p4 = np.array([w, h, 0, 0], np.float32) - pcenter
 
    dst1 = r.dot(p1)
    dst2 = r.dot(p2)
    dst3 = r.dot(p3)
    dst4 = r.dot(p4)
 
    list_dst = [dst1, dst2, dst3, dst4]
 
    org = np.array([[0, 0],
                    [w, 0],
                    [0, h],
                    [w, h]], np.float32)
 
    dst = np.zeros((4, 2), np.float32)
 
    # 投影至成像平面
    for i in range(4):
        dst[i, 0] = list_dst[i][0] * z / (z - list_dst[i][2]) + pcenter[0]
        dst[i, 1] = list_dst[i][1] * z / (z - list_dst[i][2]) + pcenter[1]
 
    warpR = cv2.getPerspectiveTransform(org, dst)
    return warpR
 
def control():
    global anglex,angley,anglez,fov,r
 
    # 键盘控制
    if 27 == c:  # Esc quit
        sys.exit()
    if c == ord('w'):
        anglex += 1
    if c == ord('s'):
        anglex -= 1
    if c == ord('a'):
        angley += 1
        print(angley)
        # dx=0
    if c == ord('d'):
        angley -= 1
    if c == ord('u'):
        anglez += 1
    if c == ord('p'):
        anglez -= 1
    if c == ord('t'):
        fov += 1
    if c == ord('r'):
        fov -= 1
    if c == ord(' '):
        anglex = angley = anglez = 0
    if c == ord('e'):
        print("======================================")
        print('Rotation Matrix:')
        print(r)
        print('angle alpha(anglex):')
        print(anglex)
        print('angle beta(angley):')
        print(angley)
        print('dz(anglez):')
        print(anglez)
 
 
while True:
 
    warpR = get_warpR()
 
    result = cv2.warpPerspective(img, warpR, (h, w))
    cv2.namedWindow('result',2)
    cv2.imshow("result", result)
    c = cv2.waitKey(30)
    control()
 
cv2.destroyAllWindows()

运行效果:

控制:

  • s控制垂直方向上的形变
  • a和d控制水平方向上的行变
  • u和p控制角度旋转
  • e 输出当前旋转矩阵参数

原文: https://blog.csdn.net/dcrmg/article/details/80273818

C++ 基于OpenCV的照片换背景色

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

void ChangeImgBG();
Mat HandleImgData(Mat &img);
/*
图片背景替换
知识点:分水岭分割、高斯模糊
处理步骤:数据组装-KMeans分割-背景消除-生成遮罩-模糊-输出
*/
void ChangeImgBG()
{
    const char *win1 = "window1";
    const char *win2 = "window2";
    const char *win3 = "window3";
    const char *win4 = "window4";
    const char *win5 = "window5";
    const char *win6 = "window6";
    namedWindow(win1, WINDOW_AUTOSIZE); //创建窗口 win1
    namedWindow(win2, WINDOW_AUTOSIZE); //创建窗口 win2
    namedWindow(win3, WINDOW_AUTOSIZE); //创建窗口 win3
    namedWindow(win4, WINDOW_AUTOSIZE); //创建窗口 win4
    namedWindow(win5, WINDOW_AUTOSIZE); //创建窗口 win5
    namedWindow(win6, WINDOW_AUTOSIZE); //创建窗口 win6

    Mat img1, img2;
    //加载图片
    img1 = imread("pph.jpg");
    if (img1.empty())
    {
        cout << "image not found..." << endl;
        exit(0); //如果图片不存在,退出程序
    }
    img2 = img1.clone();
    //显示原始图片
    imshow(win1, img1);
    //组装数据
    Mat points = HandleImgData(img1);

    //Kmeans处理
    int numCluster = 4;
    Mat labels;
    Mat centers;
    TermCriteria termCriteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);

    kmeans(points, numCluster, labels, termCriteria, 3, KMEANS_PP_CENTERS, centers);
    //遮罩
    Mat mask = Mat::zeros(img1.size(), CV_8UC1);
    int index = img1.rows * 2 + 2;
    int cindex = labels.at(index, 0); //背景设置为0
    int height = img1.rows;
    int width = img1.cols;

    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            index = row * width + col;
            int label = labels.at(index, 0);
            if (label == cindex)
            {
                img2.at(row, col)[0] = 0;
                img2.at(row, col)[1] = 0;
                img2.at(row, col)[2] = 0;
                mask.at(row, col) = 0;
            }
            else
            {
                mask.at(row, col) = 255;
            }
        }
    }

    //腐蚀
    Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    erode(mask, mask, k);
    imshow(win4, mask);

    //高斯模糊
    GaussianBlur(mask, mask, Size(3, 3), 0, 0);
    imshow(win5, mask);

    //通道混合
    RNG rng(12345);

    //背景颜色调整
    Vec3b color;
    /*color[0] = rng.uniform(255, 255);
    color[1] = rng.uniform(255, 255);
    color[2] = rng.uniform(255, 255);*/
    color[0] = 255;
    color[1] = 255;
    color[2] = 255;

    Mat result(img1.size(), img1.type());

    double d1 = 0.0;
    int r = 0, g = 0, b = 0;
    int r1 = 0, g1 = 0, b1 = 0;
    int r2 = 0, g2 = 0, b2 = 0;

    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            int m = mask.at(row, col);
            if (m == 255)
            {
                result.at(row, col) = img1.at(row, col); //前景
            }
            else if (m == 0)
            {
                result.at(row, col) = color; //背景
            }
            else
            {
                d1 = m / 255.0;
                b1 = img1.at(row, col)[0];
                g1 = img1.at(row, col)[1];
                r1 = img1.at(row, col)[2];

                b2 = color[0];
                g2 = color[1];
                r2 = color[2];

                b = b1 * d1 + b2 * (1.0 - d1);
                g = g1 * d1 + g2 * (1.0 - d1);
                r = r1 * d1 + r2 * (1.0 - d1);

                result.at(row, col)[0] = b;
                result.at(row, col)[1] = g;
                result.at(row, col)[2] = r;
            }
        }
    }

    //输出
    imshow(win2, mask);
    imshow(win3, img2);
    imshow(win6, result);
    //保存处理后的图片
    imwrite("pph_bg_white.jpg", result);
}

//组装样本数据
Mat HandleImgData(Mat &img)
{
    int width = img.cols;
    int height = img.rows;
    int count1 = width * height;
    int channels1 = img.channels();

    Mat points(count1, channels1, CV_32F, Scalar(10));
    int index = 0;
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            index = row * width + col;
            Vec3b bgr = img.at(row, col);
            points.at(index, 0) = static_cast(bgr[0]);
            points.at(index, 1) = static_cast(bgr[1]);
            points.at(index, 2) = static_cast(bgr[2]);
        }
    }
    return points;
}

int main()
{
    ChangeImgBG();

    waitKey(0);
    return 0;
}