38、OpenCV之C++教程

一、OpenCV的下载与安装

38、OpenCV之C++教程

38、OpenCV之C++教程

38、OpenCV之C++教程

下载完成后会得到一个 opencv-3.4.15-vc14_vc15.exe 文件,点击运行后会生成一个文件夹。
此文件夹为下一步工程创建使用,文件夹可移动、复制和重命名,这里命名如下:

38、OpenCV之C++教程

二、VS2019创建OpenCV基础工程

2.1、创建VS工程

38、OpenCV之C++教程

38、OpenCV之C++教程

38、OpenCV之C++教程

2.2、附加包含目录

38、OpenCV之C++教程

附加包含目录:$(SolutionDir)\OpenCV3.4.15\opencv\build\include

38、OpenCV之C++教程

附加lib库目录:$(SolutionDir)\OpenCV3.4.15\opencv\build\x64\vc15\lib

38、OpenCV之C++教程

附加dll库目录:PATH=$(SolutionDir)\OpenCV3.4.15\opencv\build\x64\vc15\bin;%PATH%

38、OpenCV之C++教程

2.3、附加依赖项

Debug模式下的依赖项:opencv_world3415d.lib

38、OpenCV之C++教程

Release模式下的依赖项:opencv_world3415.lib

38、OpenCV之C++教程

至此配置完成,开启你的OpenCV之旅吧!

三、OpenCV基本操作教程

3.1、打印版本

#include <iostream>
#include <opencv2 opencv.hpp>
int main(int argc, char** argv)
{
    std::cout << "OpenCV_Version: " << CV_VERSION << std::endl;
    cv::waitKey(0);
    return 0;
}</opencv2></iostream>

3.2、显示图像

//&#x793A;&#x4F8B;&#x4E00;:&#x4EE5;&#x539F;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x5E76;&#x663E;&#x793A;&#x56FE;&#x50CF;
#include <iostream>
#include <opencv2 opencv.hpp>
using namespace cv;
int main(int argc, char** argv)
{
    //&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    Mat img = imread("../images/liyifeng.jpg", cv::IMREAD_UNCHANGED);//&#x4EE5;&#x539F;&#x56FE;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;
    if (img.empty()) {
        std::cout << "&#x52A0;&#x8F7D;&#x56FE;&#x7247;&#x5931;&#x8D25;" << std::endl;
    }
    else {
        imshow("&#x7A97;&#x53E3;1", img);  //&#x5728;&#x7A97;&#x53E3;1&#x4E2D;&#x663E;&#x793A;&#x56FE;&#x7247;img(&#x7A97;&#x53E3;&#x5927;&#x5C0F;&#x4E0D;&#x80FD;&#x8C03;&#x6574;)
        imshow("&#x7A97;&#x53E3;2", img);  //&#x5728;&#x7A97;&#x53E3;2&#x4E2D;&#x663E;&#x793A;&#x56FE;&#x7247;img(&#x7A97;&#x53E3;&#x5927;&#x5C0F;&#x4E0D;&#x80FD;&#x8C03;&#x6574;)
    }
    waitKey(0);            //&#x663E;&#x793A;&#x56FE;&#x7247;&#x7684;&#x7A97;&#x53E3;&#x505C;&#x987F;
    //waitKey(2000);       //&#x663E;&#x793A;&#x56FE;&#x7247;&#x7684;&#x7A97;&#x53E3;&#x505C;&#x987F;2000ms
    //destroyAllWindows(); //&#x9500;&#x6BC1;&#x6240;&#x6709;&#x7684;&#x7A97;&#x53E3;
    return 0;
}</opencv2></iostream>
//&#x793A;&#x4F8B;&#x4E8C;:&#x4EE5;&#x7070;&#x5EA6;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x5E76;&#x663E;&#x793A;&#x56FE;&#x7247;
#include <iostream>
#include <opencv2 opencv.hpp>
using namespace cv;
int main(int argc, char** argv)
{
    Mat img = imread("../images/liyifeng.jpg", IMREAD_GRAYSCALE);//&#x4EE5;&#x7070;&#x5EA6;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    if (img.empty()) {
        std::cout << "&#x52A0;&#x8F7D;&#x56FE;&#x7247;&#x5931;&#x8D25;" << std::endl;
    }
    else {
        namedWindow("hello world", cv::WINDOW_FREERATIO); //&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x540D;&#x4E3A;hello world&#x7684;&#x7A97;&#x53E3;
        imshow("hello world", img); //&#x5728;hello world&#x7684;&#x7A97;&#x53E3;&#x4E0A;&#x663E;&#x793A;&#x56FE;&#x7247;img
    }
    waitKey(0);          //&#x663E;&#x793A;&#x56FE;&#x7247;&#x7684;&#x7A97;&#x53E3;&#x505C;&#x987F;
    //destroyAllWindows(); //&#x9500;&#x6BC1;&#x6240;&#x6709;&#x7684;&#x7A97;&#x53E3;
    return 0;
}
//WINDOW_FREERATIO:&#x56FE;&#x7247;&#x5E03;&#x6EE1;&#x7A97;&#x53E3;&#xFF0C;&#x7A97;&#x53E3;&#x5927;&#x5C0F;&#x4E5F;&#x53EF;&#x4EE5;&#x62C9;&#x4F38;&#x8C03;&#x6574;</opencv2></iostream>

3.3、格式转换

#include <iostream>
#include <opencv2 opencv.hpp>
using namespace cv;
int main(int argc, char** argv)
{
    //&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    Mat img_source = imread("../images/liyifeng.jpg", IMREAD_UNCHANGED);//&#x4EE5;&#x539F;&#x56FE;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;
    if (img_source.empty()) {
        std::cout << "&#x52A0;&#x8F7D;&#x56FE;&#x7247;&#x5931;&#x8D25;" << std::endl;
    }
    else {
        Mat img_hsv, img_gray;
        cvtColor(img_source, img_hsv, COLOR_BGR2HSV); //img_source&#x8F6C;HSV&#x683C;&#x5F0F;&#xFF0C;&#x7ED3;&#x679C;&#x5B58;&#x5230;img_hsv&#x4E2D;
        cvtColor(img_source, img_gray, COLOR_BGR2GRAY); //img_source&#x8F6C;&#x7070;&#x5EA6;&#x683C;&#x5F0F;&#xFF0C;&#x7ED3;&#x679C;&#x5B58;&#x5230;img_gray&#x4E2D;
        imshow("img_hsv - HSV&#x7A7A;&#x95F4;", img_hsv);
        imshow("img_gray - &#x7070;&#x5EA6;&#x7A7A;&#x95F4;", img_gray);
    }
    waitKey(0);          //&#x663E;&#x793A;&#x56FE;&#x7247;&#x7684;&#x7A97;&#x53E3;&#x505C;&#x987F;
    //destroyAllWindows(); //&#x9500;&#x6BC1;&#x6240;&#x6709;&#x7684;&#x7A97;&#x53E3;
    return 0;
}
//COLOR_BGR2GRAY = 6 : BGR&#x5230;&#x7070;&#x5EA6;
//COLOR_GRAY2BGR = 8 : &#x7070;&#x5EA6;&#x5230;BGR
//COLOR_BGR2HSV = 40 : BGR&#x5230;HSV
//COLOR_HSV2BGR = 54 : HSV&#x5230;BGR
</opencv2></iostream>

3.4、保存图像

#include <iostream>
#include <opencv2 opencv.hpp>
using namespace cv;
int main(int argc, char** argv)
{
    //&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    Mat img_source = imread("../images/liyifeng.jpg", IMREAD_UNCHANGED);//&#x4EE5;&#x539F;&#x56FE;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;
    if (img_source.empty()) {
        std::cout << "&#x52A0;&#x8F7D;&#x56FE;&#x7247;&#x5931;&#x8D25;" << std::endl;
    }
    else {
        if (imwrite("../images/liyifeng_save.jpg", img_source)){  //&#x6CE8;&#x610F;.jpg&#x662F;&#x6709;&#x635F;&#x538B;&#x7F29;,.png&#x662F;&#x65E0;&#x635F;&#x538B;&#x7F29;
            std::cout << "&#x56FE;&#x7247;&#x4FDD;&#x5B58;&#x6210;&#x529F;" << std::endl;
        }
        else {
            std::cout << "&#x56FE;&#x7247;&#x4FDD;&#x5B58;&#x5931;&#x8D25;" << std::endl;
        }
    }
    waitKey(0);          //&#x663E;&#x793A;&#x56FE;&#x7247;&#x7684;&#x7A97;&#x53E3;&#x505C;&#x987F;
    //destroyAllWindows(); //&#x9500;&#x6BC1;&#x6240;&#x6709;&#x7684;&#x7A97;&#x53E3;
    return 0;
}</opencv2></iostream>

3.5、翻转图像

3.6、几何绘制

3.7、文字绘制

3.8、Mat对象的创建

// &#x793A;&#x4F8B;&#x4E00;&#xFF1A;&#x521B;&#x5EFA;
#include <iostream>
#include <opencv2 opencv.hpp>
using namespace cv;
int main(int argc, char** argv)
{
    Mat img = Mat::zeros(Size(4, 4), CV_8UC3); //CV_8UC3:8&#x4F4D;&#x3001;unsigned char&#x3001;&#x4E09;&#x901A;&#x9053;
    namedWindow("imgx &#x7A97;&#x53E3;", WINDOW_FREERATIO); //&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x540D;&#x4E3A;"imgx &#x7A97;&#x53E3;"&#x7684;&#x7A97;&#x53E3;
    //&#x663E;&#x793A;&#x4E00;
    std::cout << "&#x663E;&#x793A;&#x4E00;&#xFF1A;&#x663E;&#x793A;&#x56FE;&#x50CF;&#x7684;&#x53C2;&#x6570;" << "\r\n";
    std::cout << img << "\r\n";                          //&#x6253;&#x5370;&#x77E9;&#x9635;
    std::cout << "dims:" << img.dims << "\r\n";          //&#x6253;&#x5370;&#x7EF4;&#x5EA6;
    std::cout << "width:" << img.cols << "\r\n";         //&#x6253;&#x5370;&#x5BBD;&#x5EA6;
    std::cout << "height:" << img.rows << "\r\n";        //&#x6253;&#x5370;&#x9AD8;&#x5EA6;
    std::cout << "size:" << img.size << "\r\n";          //&#x6253;&#x5370;&#x5C3A;&#x5BF8;
    std::cout << "total:" << img.total() << "\r\n";      //&#x6253;&#x5370;&#x50CF;&#x7D20;&#x603B;&#x6570;
    std::cout << "elemSize" << img.elemSize() << "\r\n"; //&#x77E9;&#x9635;&#x6BCF;&#x4E2A;&#x50CF;&#x7D20;&#x6240;&#x5360;&#x5B57;&#x8282;&#x6570;(&#x4E00;&#x4E2A;&#x50CF;&#x7D20;&#x4E09;&#x4E2A;&#x6570;&#x7EC4;&#x5143;&#x7D20;)
    std::cout << "channel:" << img.channels() << "\r\n"; //&#x77E9;&#x9635;&#x6BCF;&#x4E2A;&#x50CF;&#x7D20;&#x6240;&#x7528;&#x901A;&#x9053;&#x6570;(&#x4E00;&#x4E2A;&#x50CF;&#x7D20;&#x4E09;&#x4E2A;&#x6570;&#x7EC4;&#x5143;&#x7D20;)
    std::cout << "type:" << cv::typeToString(img.type()) << "\r\n";    //&#x77E9;&#x9635;&#x6BCF;&#x4E2A;&#x50CF;&#x7D20;&#x7684;&#x6570;&#x636E;&#x7C7B;&#x578B;
    std::cout << "depth:" << cv::depthToString(img.depth()) << "\r\n"; //&#x77E9;&#x9635;&#x6BCF;&#x4E2A;&#x50CF;&#x7D20;&#x7684;&#x901A;&#x9053;&#x7684;&#x6570;&#x636E;&#x7C7B;&#x578B;
    //&#x663E;&#x793A;&#x4E8C;
    std::cout << "&#x663E;&#x793A;&#x4E8C;&#xFF1A;&#x56FE;&#x50CF;&#x7684;&#x8D4B;&#x503C;&#x64CD;&#x4F5C;" << "\r\n";
    Mat imgx;
    img.copyTo(imgx);        //&#x628A;img&#x62F7;&#x8D1D;&#x4E00;&#x4EFD;&#x7ED9;imgx
    imgx = Scalar(255, 0, 0);  //imgx&#x7684;&#x6BCF;&#x4E2A;&#x50CF;&#x7D20;&#x70B9;&#x5404;&#x901A;&#x9053;&#x90FD;&#x8D4B;&#x503C;&#x6210;(0,0,255)
    std::cout << imgx << "\r\n";                          //&#x6253;&#x5370;&#x77E9;&#x9635;
    imshow("imgx &#x7A97;&#x53E3;", imgx);
    //&#x663E;&#x793A;&#x4E09;(C++&#x77E5;&#x8BC6;)
    //Mat imgy = imgx;          //&#x6D45;&#x62F7;&#x8D1D;
    //imgx.copyTo(imgy);        //&#x6761;&#x4EF6;&#x6DF1;&#x62F7;&#x8D1D;
    //Mat imgy = imgx.clone();  //&#x5B8C;&#x5168;&#x6DF1;&#x62F7;&#x8D1D;
    waitKey(0);          //&#x663E;&#x793A;&#x56FE;&#x7247;&#x7684;&#x7A97;&#x53E3;&#x505C;&#x987F;
    //destroyAllWindows(); //&#x9500;&#x6BC1;&#x6240;&#x6709;&#x7684;&#x7A97;&#x53E3;
    return 0;
}</opencv2></iostream>

3.9、Mat对象的读写

//&#x793A;&#x4F8B;: &#x904D;&#x5386;&#x4E0E;&#x8BFB;&#x5199;
#include <iostream>
#include <opencv2 opencv.hpp>
using namespace cv;
int main(int argc, char** argv)
{
    Mat image = Mat::zeros(Size(2, 2), CV_8UC3); //CV_8UC3:8&#x4F4D;&#x4E09;&#x901A;&#x9053;
    int width = image.cols; //&#x5217;
    int height = image.rows; //&#x884C;
    int channel = image.channels(); //&#x901A;&#x9053;&#x6570;
    //&#x4E00;&#x3001;&#x4FEE;&#x6539;&#x56FE;&#x50CF;&#x5404;&#x70B9;&#x50CF;&#x7D20;&#x503C;
    switch (channel) {
    case 1: {
        image.at<uchar>(0, 0) = 0x00; image.at<uchar>(0, 1) = 0xFF;
        image.at<uchar>(1, 0) = 0xFF; image.at<uchar>(1, 1) = 0x00;
        break;
    }
    case 3: { //&#x5F69;&#x8272;&#x56FE;&#x50CF;
        image.at<vec3b>(0, 0) = { 0,0,255 }; image.at<vec3b>(0, 1) = { 0,255,0 }; // 00 01
        image.at<vec3b>(1, 0) = { 255,0,0 }; image.at<vec3b>(1, 1) = { 0,0,0 };   // 10 11
        //image.at<vec3b>(row, col)[0] = 0;   //&#x5199;&#x3001;(&#x5355;&#x72EC;&#x5199;&#x4E00;&#x4E2A;&#x50CF;&#x7D20;B&#x901A;&#x9053;)
        //image.at<vec3b>(row, col)[1] = 255; //&#x5199;&#x3001;(&#x5355;&#x72EC;&#x5199;&#x4E00;&#x4E2A;&#x50CF;&#x7D20;G&#x901A;&#x9053;)
        //image.at<vec3b>(row, col)[2] = 0;   //&#x5199;&#x3001;(&#x5355;&#x72EC;&#x5199;&#x4E00;&#x4E2A;&#x50CF;&#x7D20;R&#x901A;&#x9053;)
        break;
    }
    default: {break; }
    }
    //&#x4E8C;&#x3001;&#x904D;&#x5386;&#x56FE;&#x50CF;&#x8BFB;&#x53D6;&#x50CF;&#x7D20;&#x503C;
    for (int row = 0; row < height; row++) {
        for (int col = 0; col < width; col++) {
            switch (channel) {
            case 1: {//&#x7070;&#x5EA6;&#x56FE;&#x50CF;(row=&#x884C;&#xFF0C;col=&#x5217;)
                int pv = image.at<uchar>(row, col); //&#x8BFB;
                std::cout << "row,col=" << pv << "\r\n";
                break;
            }
            case 3: { //&#x5F69;&#x8272;&#x56FE;&#x50CF;
                Vec3b bgr = image.at<vec3b>(row, col);//&#x8BFB;
                std::cout << "row,col=" << bgr << "\r\n";
                break;
            }
            default: {break; }
            }
        }
    }
    cv::namedWindow("imgx &#x7A97;&#x53E3;", WINDOW_FREERATIO); //&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x540D;&#x4E3A;"imgx &#x7A97;&#x53E3;1"&#x7684;&#x7A97;&#x53E3;
    cv::imshow("imgx &#x7A97;&#x53E3;", image);
    cv::waitKey(0); //&#x663E;&#x793A;&#x56FE;&#x7247;&#x7684;&#x7A97;&#x53E3;&#x505C;&#x987F;
    //cv::destroyAllWindows(); //&#x9500;&#x6BC1;&#x6240;&#x6709;&#x7684;&#x7A97;&#x53E3;
    return 0;
}</vec3b></uchar></vec3b></vec3b></vec3b></vec3b></vec3b></vec3b></vec3b></uchar></uchar></uchar></uchar></opencv2></iostream>

Python版本参考

opencv3.4.1.15之后的版本,在某些识别算法上商业化了,所以建议使用3.4.1.15版本的,但是由于conda和pip中已经搜不到opencv3.4.1.15的版本了,这里提供pip的离线安装包下载:
文件下载地址:https://download.csdn.net/download/BaoTTing/85133357
离线安装命令:
pip install your_folder\opencv_python-3.4.1.15-cp36-cp36m-win_amd64.whl
pip install your_folder\opencv_contrib_python-3.4.1.15-cp36-cp36m-win_amd64.whl
(说明:资源已经限制在5积分下载,不会动态调整)

P1.01、几何绘制

//&#x793A;&#x4F8B;&#x3001;&#x51E0;&#x4F55;&#x7ED8;&#x5236;
&#x8FD9;&#x662F;&#x4E00;&#x4E2A;&#x793A;&#x4F8B; Python &#x811A;&#x672C;&#x3002;
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    img = np.zeros((512, 512, 3), np.uint8)
    cv.line(img, (0, 0), (511, 511), (255, 0, 0), 5)
    cv.circle(img, (256, 256), 60, (0, 0, 255), -1)
    cv.rectangle(img, (100, 100), (400, 400), (0, 255, 0), 5)
    cv.putText(img, "hello", (100, 150), cv.FONT_HERSHEY_COMPLEX, 5, (255, 255, 255), 3)
    plt.imshow(img[:, :, ::-1])
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.02、像素修改

&#x793A;&#x4F8B;&#x3001;&#x50CF;&#x7D20;&#x4FEE;&#x6539;&#x548C;&#x683C;&#x5F0F;&#x83B7;&#x53D6;
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    img = cv.imread("ant.jpg", cv.IMREAD_UNCHANGED)
    px = img[50, 50]    # &#x83B7;&#x53D6;&#x67D0;&#x4E2A;&#x50CF;&#x7D20;&#x70B9;&#x7684;&#x503C;
    print("px = ", px)  # &#x6253;&#x5370;px&#x7684;&#x503C;
    blue = img[50, 50, 0]   # &#x4EC5;&#x83B7;&#x53D6;(50,50)&#x70B9;&#x5904;&#x50CF;&#x7D20;&#x7684;&#x84DD;&#x8272;&#x901A;&#x9053;&#x503C;
    green = img[50, 50, 1]  # &#x4EC5;&#x83B7;&#x53D6;(50,50)&#x70B9;&#x5904;&#x50CF;&#x7D20;&#x7684;&#x7EFF;&#x8272;&#x901A;&#x9053;&#x503C;
    red = img[50, 50, 2]    # &#x4EC5;&#x83B7;&#x53D6;(50,50)&#x70B9;&#x5904;&#x50CF;&#x7D20;&#x7684;&#x7EA2;&#x8272;&#x901A;&#x9053;&#x503C;
    print("(B,G,R) =", "(%d,%d,%d)" % (blue, green, red))           # &#x6253;&#x5370;&#x5404;&#x4E2A;&#x901A;&#x9053;&#x7684;&#x503C;
    print("type(img) =", type(img), ",", "img.dtype =", img.dtype)  # &#x6253;&#x5370;img&#x7684;&#x7C7B;&#x578B;&#x548C;img&#x91CC;&#x7684;&#x5143;&#x7D20;&#x7684;&#x7C7B;&#x578B;
    print("img.shape = ", img.shape)  # &#x6253;&#x5370;&#x50CF;&#x7D20;&#x5C3A;&#x5BF8;(w,h,c)
    print("img.size = ", img.size)  # &#x6253;&#x5370;&#x6570;&#x636E;&#x603B;&#x6570;(w*h*c)
    img[100, 100] = [255, 255, 255]  # &#x4FEE;&#x6539;&#x67D0;&#x4E2A;&#x4F4D;&#x7F6E;&#x7684;&#x50CF;&#x7D20;&#x503C;
    img[100, 101] = [255, 255, 255]  # &#x4FEE;&#x6539;&#x67D0;&#x4E2A;&#x4F4D;&#x7F6E;&#x7684;&#x50CF;&#x7D20;&#x503C;
    img[100, 102] = [255, 255, 255]  # &#x4FEE;&#x6539;&#x67D0;&#x4E2A;&#x4F4D;&#x7F6E;&#x7684;&#x50CF;&#x7D20;&#x503C;
    img[100, 103] = [255, 255, 255]  # &#x4FEE;&#x6539;&#x67D0;&#x4E2A;&#x4F4D;&#x7F6E;&#x7684;&#x50CF;&#x7D20;&#x503C;
    img[100, 104] = [255, 255, 255]  # &#x4FEE;&#x6539;&#x67D0;&#x4E2A;&#x4F4D;&#x7F6E;&#x7684;&#x50CF;&#x7D20;&#x503C;
    plt.imshow(img[:, :, ::-1])  # BGR&#x8F6C;RGB
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.03、边界填充

&#x793A;&#x4F8B;&#x3001;&#x8FB9;&#x754C;&#x586B;&#x5145;
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img = cv.imread("ant.jpg", cv.IMREAD_UNCHANGED)
    # 2&#x3001;&#x8FB9;&#x754C;&#x586B;&#x5145;&#x5C3A;&#x5BF8;
    top_size, bottom_size, left_size, right_size = (50, 50, 50, 50)
    # 3&#x3001;&#x8FB9;&#x754C;&#x586B;&#x5145;
    replicate = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv.BORDER_REPLICATE)  # &#x8FB9;&#x7F18;&#x590D;&#x5236;
    reflect1 = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv.BORDER_REFLECT)  # &#x53CD;&#x5C04;&#x6CD5;1
    reflect2 = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv.BORDER_REFLECT_101)  # &#x53CD;&#x5C04;&#x6CD5;2
    wrap = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv.BORDER_WRAP)  # &#x5916;&#x5305;&#x88C5;&#x6CD5;
    constant = cv.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv.BORDER_CONSTANT, value=0)  # &#x5E38;&#x91CF;&#x586B;&#x5145;
    # 5&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(10, 8), dpi=100)
    axes[0, 0].imshow(img[:, :, ::-1])
    axes[0, 0].set_title("&#x539F;&#x56FE;")
    axes[0, 1].imshow(replicate[:, :, ::-1])
    axes[0, 1].set_title("&#x8FB9;&#x7F18;&#x590D;&#x5236;")
    axes[0, 2].imshow(reflect1[:, :, ::-1])
    axes[0, 2].set_title("&#x53CD;&#x5C04;&#x6CD5;1")

    axes[1, 0].imshow(reflect2[:, :, ::-1])
    axes[1, 0].set_title("&#x53CD;&#x5C04;&#x6CD5;2")
    axes[1, 1].imshow(wrap[:, :, ::-1])
    axes[1, 1].set_title("&#x5916;&#x5305;&#x88C5;&#x6CD5;")
    axes[1, 2].imshow(constant[:, :, ::-1])
    axes[1, 2].set_title("&#x5E38;&#x91CF;&#x586B;&#x5145;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.04、通道分割

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x7684;&#x5206;&#x5272;&#x4E0E;&#x5408;&#x5E76;
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    img = cv.imread("ant.jpg", cv.IMREAD_UNCHANGED)
    b, g, r = cv.split(img)  # &#x901A;&#x9053;&#x62C6;&#x5206;
    img = cv.merge((b, g, r))  # &#x901A;&#x9053;&#x5408;&#x5E76;
    plt.subplot(1, 2, 1)
    plt.imshow(b)
    img = img[:, :, ::-1]  # BGR&#x8F6C;RGB
    plt.subplot(1, 2, 2)
    plt.imshow(img)  # &#x5BF9;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x5904;&#x7406;
    plt.show()  # &#x5BF9;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x663E;&#x793A;
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.05、格式转换

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x683C;&#x5F0F;&#x7684;&#x8F6C;&#x6362;&#x3001;&#x8272;&#x5F69;&#x7A7A;&#x95F4;
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    input_img = cv.imread("ant.jpg", cv.IMREAD_UNCHANGED)

    img_hsv = cv.cvtColor(input_img, cv.COLOR_BGR2HSV)
    img_gray = cv.cvtColor(input_img, cv.COLOR_BGR2GRAY)

    plt.subplot(1, 2, 1)
    plt.imshow(img_hsv)
    plt.subplot(1, 2, 2)
    plt.imshow(img_gray, cmap=plt.cm.gray)
    plt.show()  # &#x5BF9;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x663E;&#x793A;
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.06、图像加法

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x7684;&#x52A0;&#x6CD5;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x6570;&#x503C;&#x52A0;&#x6CD5;
    # numpy&#x7684;&#x52A0;&#x6CD5;&#x662F;&#x9971;&#x548C;&#x53D6;&#x6A21;&#x8FD0;&#x7B97;&#x3001;&#x8D85;&#x8FC7;&#x8FB9;&#x754C;&#x53D6;&#x6A21;&#x503C;
    # OpenCV&#x7684;&#x52A0;&#x6CD5;&#x662F;&#x9971;&#x548C;&#x53D6;&#x8FB9;&#x754C;&#x64CD;&#x4F5C;&#x3001;&#x8D85;&#x8FC7;&#x8FB9;&#x754C;&#x53D6;&#x8FB9;&#x754C;&#x503C;
    x = np.uint8([250])
    y = np.uint8([10])
    print("numpy add=", x+y)            # numpy-> 250 + 10 = 260%256 = 4
    print("OpenCV add=", cv.add(x, y))  # OpenCV-> 250 + 10 = 255
    # &#x5BF9;&#x6BD4;&#x4E24;&#x79CD;&#x52A0;&#x6CD5;,&#x53EF;&#x89C1;OpenCV&#x7684;&#x52A0;&#x6CD5;&#x66F4;&#x5E38;&#x7528;(&#x51CF;&#x6CD5;&#x4E5F;&#x662F;cv&#x6BD4;&#x8F83;&#x5E38;&#x7528;)
    # 2&#x3001;&#x56FE;&#x50CF;&#x52A0;&#x6CD5;
    img1 = cv.imread("view.jpg")
    img2 = cv.imread("rain.jpg")
    npadd_img = img1 + img2
    cvadd_img = cv.add(img1, img2)
    # 3&#x3001;&#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
    axes[0].imshow(npadd_img[:, :, ::-1])
    axes[0].set_title("np add")
    axes[1].imshow(cvadd_img[:, :, ::-1])
    axes[1].set_title("cv add")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.07、图像混合

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x7684;&#x6DF7;&#x5408;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # &#x56FE;&#x50CF;&#x7684;&#x6DF7;&#x5408;&#x4E5F;&#x662F;&#x52A0;&#x6CD5;&#xFF0C;&#x4E0D;&#x540C;&#x7684;&#x662F;&#x4E24;&#x5E45;&#x56FE;&#x50CF;&#x7684;&#x6743;&#x91CD;&#x4E0D;&#x540C;&#xFF0C;&#x7ED9;&#x4EBA;&#x4E00;&#x79CD;&#x6DF7;&#x5408;&#x6216;&#x8005;&#x900F;&#x660E;&#x7684;&#x611F;&#x89C9;&#x3002;
    # &#x5373; g(x) = (1-a)*f0(x)+a*f1(x),&#x6539;&#x53D8;a&#x7684;&#x503C;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x975E;&#x5E38;&#x70AB;&#x9177;&#x7684;&#x6DF7;&#x5408;&#x3002;
    # cv2.addWeight()&#x53EF;&#x4EE5;&#x6309;&#x516C;&#x5F0F;: dst = a*img1+b*img2+c&#x8FDB;&#x884C;&#x6DF7;&#x5408;(&#x53D6;c=0&#x5373;&#x53EF;)&#x3002;
    img1 = cv.imread("view.jpg")
    img2 = cv.imread("rain.jpg")
    img_blend_1 = cv.addWeighted(img1, 0.7, img2, 0.3, 0)
    img_blend_2 = cv.addWeighted(img1, 0.3, img2, 0.7, 0)
    # &#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
    axes[0].imshow(img_blend_1[:, :, ::-1])
    axes[0].set_title("a=0.7,b=0.3,c=0")
    axes[1].imshow(img_blend_2[:, :, ::-1])
    axes[1].set_title("a=0.3,b=0.7,c=0")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.08、图像缩放

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x7F29;&#x653E;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x56FE;&#x50CF;&#x7F29;&#x653E;&#xFF1A;&#x5BF9;&#x56FE;&#x50CF;&#x7684;&#x5927;&#x5C0F;&#x8FDB;&#x884C;&#x8C03;&#x6574;&#xFF0C;&#x5373;&#x56FE;&#x50CF;&#x7684;&#x653E;&#x5927;&#x6216;&#x8005;&#x7F29;&#x5C0F;
&#x51FD;&#x6570;&#xFF1A;cv2.resize(src,desize,fx=0,fy=0,interpolation=cv2.INTER_LINEAR)
src:&#x8F93;&#x5165;&#x56FE;&#x50CF;
dsize:&#x7EDD;&#x5BF9;&#x5C3A;&#x5BF8;,&#x76F4;&#x63A5;&#x6307;&#x5B9A;&#x8C03;&#x6574;&#x540E;&#x56FE;&#x50CF;&#x5927;&#x5C0F;
fx,fy:&#x76F8;&#x5BF9;&#x5C3A;&#x5BF8;,&#x5C06;desize&#x8BBE;&#x7F6E;&#x4E3A;None,&#x7136;&#x540E;&#x5C06;fx,fy&#x8BBE;&#x7F6E;&#x4E3A;&#x6BD4;&#x4F8B;&#x56E0;&#x5B50;&#x5373;&#x53EF;
interpolation:&#x63D2;&#x503C;&#x65B9;&#x6CD5;
  cv2.INTER_LINEAR:&#x53CC;&#x7EBF;&#x6027;&#x63D2;&#x503C;&#x6CD5;
  cv2.INTER_NEAREST:&#x6700;&#x8FD1;&#x90BB;&#x63D2;&#x503C;
  cv2.INTER_AREA:&#x50CF;&#x7D20;&#x533A;&#x57DF;&#x91CD;&#x91C7;&#x6837;
  cv2.INTER_CUBIC:&#x53CC;&#x4E09;&#x6B21;&#x63D2;&#x503C;&#x6CD5;
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    img_src = cv.imread("kids.jpg")
    rows, cols = img_src.shape[:2]
    print("img_src_size:", img_src.shape)
    # &#x7EDD;&#x5BF9;&#x5C3A;&#x5BF8;
    img_abs = cv.resize(img_src, (2 * cols, 2 * rows), interpolation=cv.INTER_CUBIC)
    print("img_abs_size:", img_abs.shape)
    # &#x76F8;&#x5BF9;&#x5C3A;&#x5BF8;
    img_com = cv.resize(img_src, None, fx=0.5, fy=0.5)
    print("img_com_size:", img_com.shape)
    # 1&#x3001;&#x4F7F;&#x7528;cv&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    cv.imshow("img_src", img_src)
    cv.imshow("img_abs", img_abs)
    cv.imshow("img_com", img_com)
    cv.waitKey(0)
    # 2&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    # fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
    # axes[0].imshow(img_src[:, :, ::-1])
    # axes[0].set_title("&#x539F;&#x59CB;&#x56FE;&#x7247;(&#x653E;&#x5927;)")
    # axes[1].imshow(img_abs[:, :, ::-1])
    # axes[1].set_title("&#x7EDD;&#x5BF9;&#x5C3A;&#x5BF8;(&#x653E;&#x5927;)")
    # axes[2].imshow(img_com[:, :, ::-1])
    # axes[2].set_title("&#x76F8;&#x5BF9;&#x5C3A;&#x5BF8;(&#x7F29;&#x5C0F;)")
    # plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.09、图像平移

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x5E73;&#x79FB;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x56FE;&#x50CF;&#x5E73;&#x79FB;&#xFF1A;&#x5C06;&#x56FE;&#x50CF;&#x6309;&#x7167;&#x6307;&#x5B9A;&#x7684;&#x65B9;&#x5411;&#x548C;&#x8DDD;&#x79BB;&#xFF0C;&#x79FB;&#x52A8;&#x76F8;&#x5E94;&#x7684;&#x4F4D;&#x7F6E;
&#x51FD;&#x6570;&#xFF1A;cv2.wrapAffine(img, M, dsize)
img:&#x8F93;&#x5165;&#x56FE;&#x50CF;
M:2*3&#x7684;&#x79FB;&#x52A8;&#x77E9;&#x9635;&#xFF0C;&#x5BF9;&#x4E8E;(x, y)&#x5904;&#x7684;&#x50CF;&#x7D20;&#x70B9;, &#x8981;&#x628A;&#x5B83;&#x79FB;&#x52A8;&#x5230;(x+tx,y+ty&#x5904;)&#xFF0C;&#x4F7F;&#x7528;&#x5982;&#x4E0B;&#x77E9;&#x9635;
  M = [ 1 0 tx]
      [ 0 1 ty]
&#x6CE8;&#x610F;&#xFF1A;&#x5C06;M&#x8BBE;&#x7F6E;&#x4E3A;np.float32&#x7C7B;&#x578B;&#x7684;Numpy&#x6570;&#x7EC4;
desize: &#x8F93;&#x51FA;&#x56FE;&#x50CF;&#x7684;&#x5927;&#x5C0F;&#xFF0C;&#x5B83;&#x662F;(width,height)&#x7684;&#x5F62;&#x5F0F;&#xFF0C;&#x5373;(&#x5217;&#x6570;&#xFF0C;&#x884C;&#x6570;)
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    img_src = cv.imread("kids.jpg")
    rows, cols = img_src.shape[:2]
    print("img_src_size:", img_src.shape)
    # &#x56FE;&#x50CF;&#x5E73;&#x79FB;
    M = np.float32([[1, 0, 100], [0, 1, 50]])
    img_trans1 = cv.warpAffine(img_src, M, (cols, rows))
    img_trans2 = cv.warpAffine(img_src, M, (2*cols, 2*rows))
    print("img_trans1_size:", img_trans1.shape)
    print("img_trans2_size:", img_trans1.shape)
    # 1&#x3001;&#x4F7F;&#x7528;cv&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    cv.imshow("img_src", img_src)
    cv.imshow("img_trans1", img_trans1)
    cv.imshow("img_trans2", img_trans2)
    cv.waitKey(0)
    # 2&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    # fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
    # axes[0].imshow(img_src[:, :, ::-1])
    # axes[0].set_title("&#x539F;&#x59CB;&#x56FE;&#x7247;")
    # axes[1].imshow(img_trans1[:, :, ::-1])
    # axes[1].set_title("&#x5E73;&#x79FB;&#x56FE;&#x7247;1")
    # axes[2].imshow(img_trans2[:, :, ::-1])
    # axes[2].set_title("&#x5E73;&#x79FB;&#x56FE;&#x7247;2")
    # plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.10、图像旋转

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x65CB;&#x8F6C;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
API&#x51FD;&#x6570;1:cv2.getRotationMatrix2D(center&#xFF0C;angle&#xFF0C;scale) &#x83B7;&#x53D6;&#x65CB;&#x8F6C;&#x77E9;&#x9635;
  center:&#x65CB;&#x8F6C;&#x4E2D;&#x5FC3;
  angle:&#x65CB;&#x8F6C;&#x89D2;&#x5EA6;
  scale:&#x7F29;&#x653E;&#x6BD4;&#x4F8B;
API&#x51FD;&#x6570;2:cv2.wrapAffine() &#x7528;&#x6CD5;&#x89C1;&#x793A;&#x4F8B;&#x516B;
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    img_src = cv.imread("kids.jpg")
    rows, cols = img_src.shape[:2]
    print("img_src_size:", img_src.shape)
    # &#x56FE;&#x50CF;&#x65CB;&#x8F6C;
    M = cv.getRotationMatrix2D((cols/2, rows/2), 45, 1.0)  # &#x83B7;&#x53D6;&#x65CB;&#x8F6C;&#x77E9;&#x9635;
    img_rotate = cv.warpAffine(img_src, M, (cols, rows))
    print("img_rotate_size:", img_rotate.shape)
    # &#x4F7F;&#x7528;cv&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    cv.imshow("img_src", img_src)
    cv.imshow("img_rotate", img_rotate)
    cv.waitKey(0)
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.11、仿射变换

&#x793A;&#x4F8B;&#x3001;&#x4EFF;&#x5C04;&#x53D8;&#x6362;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4EFF;&#x5C04;&#x53D8;&#x6362;&#x6D89;&#x53CA;&#x56FE;&#x50CF;&#x7684;&#x5F62;&#x72B6;&#x4F4D;&#x7F6E;&#x89D2;&#x5EA6;&#x7684;&#x53D8;&#x5316;&#xFF0C;&#x662F;&#x6DF1;&#x5EA6;&#x5B66;&#x4E60;&#x4E0E;&#x9884;&#x5904;&#x7406;&#x4E2D;&#x5E38;&#x7528;&#x5230;&#x7684;&#x529F;&#x80FD;&#xFF0C;&#x4EFF;&#x5C04;&#x53D8;&#x6362;&#x4E3B;&#x8981;&#x662F;&#x5BF9;&#x56FE;&#x50CF;&#x7684;&#x7F29;&#x653E;&#x3001;&#x65CB;&#x8F6C;&#x3001;&#x7FFB;&#x8F6C;&#x3001;&#x5E73;&#x79FB;&#x7B49;&#x64CD;&#x4F5C;&#x7684;&#x7EC4;&#x5408;
&#x5728;OpenCV&#x4E2D;,&#x4EFF;&#x5C04;&#x53D8;&#x6362;&#x662F;&#x4E00;&#x4E2A;2*3&#x7684;&#x77E9;&#x9635; M=[A B] <其实就是建立一种映射关系a->B>
API&#x51FD;&#x6570;1&#xFF1A;cv2.getAffineTransform(src, dst) &#x83B7;&#x53D6;&#x4EFF;&#x5C04;&#x53D8;&#x6362;&#x77E9;&#x9635;
src:&#x539F;&#x5750;&#x6807;
dst:&#x6620;&#x5C04;&#x5750;&#x6807;
API&#x51FD;&#x6570;2:cv2.wrapAffine() &#x7528;&#x6CD5;&#x89C1;&#x793A;&#x4F8B;&#x516B;
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img_src = cv.imread("kids.jpg")
    print("img_src_size:", img_src.shape)
    # 2&#x3001;&#x4EFF;&#x5C04;&#x53D8;&#x6362;
    rows, cols = img_src.shape[:2]
    # 2.1&#x3001;&#x521B;&#x5EFA;&#x53D8;&#x6362;&#x77E9;&#x9635;
    pst1 = np.float32([[50, 50], [200, 50], [50, 200]])
    pst2 = np.float32([[100, 100], [200, 50], [100, 250]])
    M = cv.getAffineTransform(pst1, pst2)
    # 2.2&#x3001;&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x7684;&#x4EFF;&#x5C04;&#x53D8;&#x6362;
    img_dst = cv.warpAffine(img_src, M, (cols, rows))
    print("img_rotate_size:", img_dst.shape)
    # 1&#x3001;&#x4F7F;&#x7528;cv&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    cv.imshow("img_src", img_src)
    cv.imshow("img_rotate", img_dst)
    cv.waitKey(0)
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;
</其实就是建立一种映射关系a->

P1.12、透射变换

&#x793A;&#x4F8B;&#x3001;&#x900F;&#x5C04;&#x53D8;&#x6362;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x900F;&#x5C04;&#x53D8;&#x6362;&#x662F;&#x89C6;&#x89D2;&#x53D8;&#x5316;&#x7684;&#x7ED3;&#x679C;&#xFF0C;&#x662F;&#x6307;&#x5229;&#x7528;&#x900F;&#x89C6;&#x4E2D;&#x5FC3;&#x3001;&#x50CF;&#x70B9;&#x3001;&#x76EE;&#x6807;&#x70B9;&#x3001;&#x4E09;&#x70B9;&#x5171;&#x7EBF;&#x7684;&#x6761;&#x4EF6;&#xFF0C;&#x6309;&#x7167;&#x900F;&#x89C6;&#x53D8;&#x6362;&#x5B9A;&#x5F8B;&#x4F7F;&#x5F97;&#x900F;
&#x89C6;&#x9762;(&#x627F;&#x5F71;&#x9762;)&#x7ED5;&#x8FF9;&#x7EBF;(&#x900F;&#x89C6;&#x8F74;)&#x65CB;&#x8F6C;&#x67D0;&#x4E00;&#x89D2;&#x5EA6;&#xFF0C;&#x7834;&#x574F;&#x539F;&#x6709;&#x7684;&#x6295;&#x5F71;&#x5149;&#x675F;&#xFF0C;&#x4ECD;&#x80FD;&#x4FDD;&#x6301;&#x627F;&#x5F71;&#x9762;&#x4E0A;&#x6295;&#x5F71;&#x51E0;&#x4F55;&#x4E0D;&#x53D8;&#x7684;&#x53D8;&#x6362;&#x3002;
API&#x51FD;&#x6570;1:cv2.getPerspectiveTransform(pts1, pts2)
API&#x51FD;&#x6570;2:cv2.wrapPerspective() &#x7528;&#x6CD5;&#x89C1;&#x793A;&#x4F8B;&#x516B;
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img_src = cv.imread("kids.jpg")
    print("img_src_size:", img_src.shape)
    # 2&#x3001;&#x6295;&#x5C04;&#x53D8;&#x6362;
    rows, cols = img_src.shape[:2]
    # 2.1&#x3001;&#x521B;&#x5EFA;&#x53D8;&#x6362;&#x77E9;&#x9635;
    pst1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
    pst2 = np.float32([[100, 145], [300, 100], [80, 290], [310, 300]])
    M = cv.getPerspectiveTransform(pst1, pst2)
    # 2.2&#x3001;&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x7684;&#x4EFF;&#x5C04;&#x53D8;&#x6362;
    img_dst = cv.warpPerspective(img_src, M, (cols, rows))
    print("img_rotate_size:", img_dst.shape)
    # 1&#x3001;&#x4F7F;&#x7528;cv&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    cv.imshow("img_src", img_src)
    cv.imshow("img_rotate", img_dst)
    cv.waitKey(0)
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.13、图像金字塔

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x91D1;&#x5B57;&#x5854;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x56FE;&#x50CF;&#x91D1;&#x5B57;&#x5854;&#x662F;&#x56FE;&#x50CF;&#x591A;&#x5C3A;&#x5BF8;&#x8868;&#x8FBE;,&#x7C7B;&#x4F3C;OpenGL&#x4E2D;&#x7684;mip&#x7EB9;&#x7406;,&#x4EE5;&#x591A;&#x79CD;&#x5206;&#x8FA8;&#x7387;&#x6765;&#x89E3;&#x91CA;&#x56FE;&#x50CF;&#x7684;&#x6709;&#x6548;&#x8868;&#x8FBE;
&#x56FE;&#x50CF;&#x91D1;&#x5B57;&#x5854;&#x7528;&#x4E8E;&#x673A;&#x5668;&#x89C6;&#x89C9;&#x548C;&#x56FE;&#x50CF;&#x538B;&#x7F29;,&#x4E00;&#x5E45;&#x56FE;&#x50CF;&#x91D1;&#x5B57;&#x5854;&#x662F;&#x4E00;&#x7CFB;&#x5217;&#x4EE5;&#x91D1;&#x5B57;&#x5854;&#x5F62;&#x72B6;&#x6392;&#x5217;&#x7684;&#x5206;&#x8FA8;&#x7387;&#x9010;&#x6E10;&#x964D;&#x4F4E;
&#x4E14;&#x6765;&#x6E90;&#x4E8E;&#x540C;&#x4E00;&#x5F20;&#x539F;&#x59CB;&#x56FE;&#x7684;&#x56FE;&#x50CF;&#x96C6;&#x5408;,&#x5176;&#x901A;&#x8FC7;&#x68AF;&#x6B21;&#x5411;&#x4E0B;&#x91C7;&#x6837;&#x83B7;&#x5F97;,&#x76F4;&#x5230;&#x8FBE;&#x5230;&#x67D0;&#x4E2A;&#x7EC8;&#x6B62;&#x6761;&#x4EF6;&#x624D;&#x505C;&#x6B62;&#x91C7;&#x6837;
&#x91D1;&#x5B57;&#x5854;&#x7684;&#x5E95;&#x90E8;&#x662F;&#x5F85;&#x5904;&#x7406;&#x7684;&#x56FE;&#x50CF;&#x9AD8;&#x5206;&#x8FA8;&#x7387;&#x8868;&#x793A;,&#x800C;&#x9876;&#x90E8;&#x662F;&#x4F4E;&#x5206;&#x8FA8;&#x7387;&#x7684;&#x8FD1;&#x4F3C;,&#x56FE;&#x50CF;&#x8D8A;&#x9AD8;,&#x5206;&#x8FA8;&#x7387;&#x8D8A;&#x4F4E;
API&#x51FD;&#x6570;1&#x3001;cv.pyrUp(img)   #&#x5BF9;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x4E0A;&#x91C7;&#x6837;,&#x5206;&#x8FA8;&#x7387;&#x589E;&#x5927;
API&#x51FD;&#x6570;2&#x3001;cv.pyrDown(img) #&#x5BF9;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x4E0B;&#x91C7;&#x6837;,&#x5206;&#x8FA8;&#x7387;&#x964D;&#x4F4E;
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img_src = cv.imread("kids.jpg")
    print("img_src_size:", img_src.shape)
    # 2&#x3001;&#x56FE;&#x50CF;&#x91D1;&#x5B57;&#x5854;
    rows, cols = img_src.shape[:2]
    # 2.1&#x3001;&#x56FE;&#x7247;&#x4E0A;&#x91C7;&#x6837;
    img_Up = cv.pyrUp(img_src)
    print("img_Up_size:", img_Up.shape)
    # 2.2&#x3001;&#x56FE;&#x50CF;&#x4E0B;&#x91C7;&#x6837;
    img_Down = cv.pyrDown(img_src)
    print("img_Down_size:", img_Down.shape)
    # 1&#x3001;&#x4F7F;&#x7528;cv&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    cv.imshow("img_Up", img_Up)
    cv.imshow("img_src", img_src)
    cv.imshow("img_Down", img_Down)
    cv.waitKey(0)
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.14、腐蚀与膨胀

&#x793A;&#x4F8B;&#x3001;&#x8150;&#x8680;&#x4E0E;&#x81A8;&#x80C0;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x56FE;&#x50CF;&#x90BB;&#x63A5;:&#x6BCF;&#x4E2A;&#x50CF;&#x7D20;&#x5468;&#x56F4;&#x6709;8&#x4E2A;&#x90BB;&#x63A5;&#x50CF;&#x7D20;,&#x5E38;&#x89C1;&#x7684;&#x90BB;&#x63A5;&#x5173;&#x7CFB;&#x6709;4&#x90BB;&#x63A5;&#x3001;8&#x90BB;&#x63A5;&#x3001;D&#x90BB;&#x63A5;
&#x56FE;&#x50CF;&#x7684;&#x8FDE;&#x901A;:1&#x3001;&#x4E24;&#x4E2A;&#x50CF;&#x7D20;&#x662F;&#x5426;&#x76F8;&#x90BB;&#x3002;2&#x3001;&#x4E24;&#x4E2A;&#x50CF;&#x7D20;&#x7684;&#x50CF;&#x7D20;&#x503C;&#x662F;&#x5426;&#x6EE1;&#x8DB3;&#x7279;&#x5B9A;&#x7684;&#x76F8;&#x4F3C;&#x51C6;&#x5219;
  4&#x8FDE;&#x901A;:&#x5BF9;&#x4E8E;&#x5177;&#x6709;&#x503C;V&#x7684;&#x50CF;&#x7D20;p&#x548C;q,&#x5982;&#x679C;q&#x5728;p&#x7684;4&#x90BB;&#x63A5;&#x4E2D;,&#x5219;&#x79F0;&#x8FD9;&#x4E24;&#x4E2A;&#x50CF;&#x7D20;&#x4E3A;4&#x8FDE;&#x901A;
  8&#x8FDE;&#x901A;:&#x5BF9;&#x4E8E;&#x5177;&#x6709;&#x503C;V&#x7684;&#x50CF;&#x7D20;p&#x548C;q,&#x5982;&#x679C;q&#x5728;p&#x7684;8&#x90BB;&#x63A5;&#x4E2D;,&#x5219;&#x79F0;&#x8FD9;&#x4E24;&#x4E2A;&#x50CF;&#x7D20;&#x4E3A;8&#x8FDE;&#x901A;
  m&#x8FDE;&#x901A;:&#x5BF9;&#x4E8E;&#x5177;&#x6709;&#x503C;V&#x7684;&#x50CF;&#x7D20;p&#x548C;q,&#x5982;&#x679C;q&#x5728;p&#x7684;4&#x90BB;&#x63A5;&#x6216;D&#x90BB;&#x63A5;&#x4E2D;,&#x4E14;p&#x7684;4&#x90BB;&#x63A5;&#x548C;q&#x7684;4&#x90BB;&#x63A5;&#x4E0D;&#x76F8;&#x4EA4;(&#x4EA4;&#x96C6;&#x4E2D;&#x6CA1;&#x6709;&#x503C;&#x4E3A;V&#x7684;&#x50CF;&#x7D20;),&#x5219;&#x79F0;&#x8FD9;&#x4E24;&#x4E2A;&#x50CF;&#x7D20;&#x4E3A;m&#x8FDE;&#x901A;
&#x8150;&#x8680;&#xFF1A;&#x5C40;&#x90E8;&#x6700;&#x5C0F;&#x503C;,(&#x6D88;&#x9664;&#x7269;&#x4F53;&#x7684;&#x8FB9;&#x754C;&#x70B9;,&#x4F7F;&#x76EE;&#x6807;&#x7F29;&#x5C0F;,&#x53EF;&#x7528;&#x4E8E;&#x6D88;&#x9664;&#x5C0F;&#x4E8E;&#x7ED3;&#x6784;&#x5143;&#x7D20;&#x7684;&#x566A;&#x58F0;&#x70B9;)
&#x81A8;&#x80C0;&#xFF1A;&#x5C40;&#x90E8;&#x6700;&#x5927;&#x503C;,(&#x5C06;&#x4E0E;&#x7269;&#x4F53;&#x63A5;&#x89E6;&#x7684;&#x6240;&#x6709;&#x80CC;&#x666F;&#x70B9;&#x5408;&#x5E76;&#x5230;&#x7269;&#x4F53;&#x4E2D;,&#x4F7F;&#x76EE;&#x6807;&#x589E;&#x5927;,&#x53EF;&#x586B;&#x8865;&#x76EE;&#x6807;&#x4E2D;&#x7684;&#x5B54;&#x6D1E;)
API&#x51FD;&#x6570;1:cv2.erode(img, kernel, iterations)
API&#x51FD;&#x6570;2:cv2.dilate(img, kernel, iterations)
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img_src = cv.imread("letter.png")
    print("img_src_size:", img_src.shape)
    # 2&#x3001;&#x521B;&#x5EFA;&#x6838;&#x7ED3;&#x6784;
    kernel = np.ones((5, 5), np.uint8)
    # 3&#x3001;&#x56FE;&#x50CF;&#x8150;&#x8680;
    img_erode = cv.erode(img_src, kernel)
    # 4&#x3001;&#x56FE;&#x7247;&#x81A8;&#x80C0;
    img_dilate = cv.dilate(img_src, kernel)
    # 5&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
    axes[0].imshow(img_src[:, :, ::-1])
    axes[0].set_title("img_src")
    axes[1].imshow(img_erode[:, :, ::-1])
    axes[1].set_title("img_erode")
    axes[2].imshow(img_dilate[:, :, ::-1])
    axes[2].set_title("img_dilate")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.15、开、闭操作

&#x793A;&#x4F8B;&#x3001;&#x5F00;&#x3001;&#x95ED;&#x64CD;&#x4F5C;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x5F00;&#x64CD;&#x4F5C;&#x662F;&#x5148;&#x8150;&#x8680;&#x540E;&#x81A8;&#x80C0;,&#x4F5C;&#x7528;&#x662F;&#x5206;&#x79BB;&#x7269;&#x4F53;,&#x6D88;&#x9664;&#x5C0F;&#x533A;&#x57DF;,&#x6D88;&#x9664;&#x566A;&#x70B9;,&#x53BB;&#x9664;&#x5C0F;&#x7684;&#x5E72;&#x6270;&#x5757;&#x3002;
&#x95ED;&#x64CD;&#x4F5C;&#x662F;&#x5148;&#x81A8;&#x80C0;&#x540E;&#x8150;&#x8680;,&#x4F5C;&#x7528;&#x662F;&#x6D88;&#x9664;&#x95ED;&#x5408;&#x7269;&#x4F53;&#x91CC;&#x9762;&#x7684;&#x5B54;&#x6D1E;,&#x53EF;&#x4EE5;&#x586B;&#x5145;&#x95ED;&#x5408;&#x533A;&#x57DF;
API&#x51FD;&#x6570;:cv2.morphologyEx(img, op, kernel)
op=cv2.MORPH_OPEN:&#x5F00;&#x64CD;&#x4F5C;
op=cv2.MORPH_CLOSE:&#x95ED;&#x64CD;&#x4F5C;
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img_src1 = cv.imread("letteropen.png")
    img_src2 = cv.imread("letterclose.png")
    print("img_src1_size:", img_src1.shape)
    print("img_src2_size:", img_src2.shape)
    # 2&#x3001;&#x521B;&#x5EFA;&#x6838;&#x7ED3;&#x6784;
    kernel = np.ones((10, 10), np.uint8)
    # 3&#x3001;&#x56FE;&#x50CF;&#x5F00;&#x64CD;&#x4F5C;
    img_src1_open = cv.morphologyEx(img_src1, cv.MORPH_OPEN, kernel)
    # 4&#x3001;&#x56FE;&#x7247;&#x95ED;&#x64CD;&#x4F5C;
    img_src2_close = cv.morphologyEx(img_src2, cv.MORPH_CLOSE, kernel)
    # 5&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8), dpi=100)
    axes[0, 0].imshow(img_src1[:, :, ::-1])
    axes[0, 0].set_title("&#x539F;&#x56FE;1")
    axes[0, 1].imshow(img_src1_open[:, :, ::-1])
    axes[0, 1].set_title("&#x539F;&#x56FE;1&#x5F00;&#x64CD;&#x4F5C;")
    axes[1, 0].imshow(img_src2[:, :, ::-1])
    axes[1, 0].set_title("&#x539F;&#x56FE;2")
    axes[1, 1].imshow(img_src2_close[:, :, ::-1])
    axes[1, 1].set_title("&#x539F;&#x56FE;2&#x95ED;&#x64CD;&#x4F5C;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.16、礼帽与黑帽

&#x793A;&#x4F8B;&#x3001;&#x793C;&#x5E3D;&#x4E0E;&#x9ED1;&#x5E3D;&#x64CD;&#x4F5C;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x793C;&#x5E3D;&#x64CD;&#x4F5C;&#xFF1A;&#x539F;&#x56FE;&#x50CF;&#x4E0E;&#x5F00;&#x8FD0;&#x7B97;&#x7684;&#x7ED3;&#x679C;&#x5DEE;(dst=src-open(src,element))
  &#x5F00;&#x8FD0;&#x7B97;&#x7684;&#x7ED3;&#x679C;&#x662F;&#x653E;&#x5927;&#x4E86;&#x88C2;&#x7F1D;&#x6216;&#x5C40;&#x90E8;&#x4F4E;&#x4EAE;&#x5EA6;&#x533A;&#x57DF;,&#x56E0;&#x6B64;,&#x4ECE;&#x539F;&#x56FE;&#x4E2D;&#x51CF;&#x53BB;&#x5F00;&#x8FD0;&#x7B97;&#x7684;&#x56FE;,&#x5F97;&#x5230;&#x7684;&#x6548;&#x679C;&#x7A81;&#x51FA;&#x4E86;&#x6BD4;&#x539F;&#x56FE;&#x8F6E;&#x5ED3;&#x5468;&#x56F4;&#x533A;&#x57DF;&#x66F4;&#x660E;&#x4EAE;&#x7684;&#x533A;&#x57DF;,&#x4E14;&#x8FD9;&#x4E00;&#x64CD;&#x4F5C;&#x548C;&#x9009;&#x62E9;&#x6838;&#x7684;&#x5927;&#x5C0F;&#x76F8;&#x5173;&#x3002;
  &#x793C;&#x8C8C;&#x8FD0;&#x7B97;&#x7528;&#x6765;&#x5206;&#x79BB;&#x6BD4;&#x4E34;&#x8FD1;&#x70B9;&#x4EAE;&#x4E00;&#x4E9B;&#x7684;&#x6591;&#x5757;,&#x5F53;&#x4E00;&#x5E45;&#x56FE;&#x50CF;&#x5177;&#x6709;&#x5927;&#x5E45;&#x7684;&#x80CC;&#x666F;&#x7684;&#x65F6;&#x5019;,&#x800C;&#x5FAE;&#x5C0F;&#x7269;&#x54C1;&#x6BD4;&#x8F83;&#x6709;&#x89C4;&#x5F8B;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;&#x9876;&#x5E3D;&#x8FD0;&#x7B97;&#x8FDB;&#x884C;&#x80CC;&#x666F;&#x63D0;&#x53D6;&#x3002;
&#x9ED1;&#x5E3D;&#x64CD;&#x4F5C;&#xFF1A;&#x95ED;&#x8FD0;&#x7B97;&#x4E0E;&#x539F;&#x56FE;&#x50CF;&#x7684;&#x7ED3;&#x679C;&#x5DEE;(dst=close(src,element)-src)
  &#x9ED1;&#x5E3D;&#x8FD0;&#x7B97;&#x540E;&#x7684;&#x6548;&#x679C;&#x56FE;&#x7A81;&#x51FA;&#x4E86;&#x6BD4;&#x539F;&#x56FE;&#x8F6E;&#x5ED3;&#x5468;&#x56F4;&#x7684;&#x533A;&#x57DF;&#x66F4;&#x6697;&#x7684;&#x533A;&#x57DF;&#xFF0C;&#x4E14;&#x8FD9;&#x4E00;&#x64CD;&#x4F5C;&#x548C;&#x9009;&#x62E9;&#x7684;&#x6838;&#x7684;&#x5927;&#x5C0F;&#x76F8;&#x5173;&#x3002;&#x9ED1;&#x5E3D;&#x8FD0;&#x7B97;&#x7528;&#x6765;&#x5206;&#x79BB;&#x6BD4;&#x90BB;&#x8FD1;&#x70B9;&#x6697;&#x4E00;&#x4E9B;&#x7684;&#x6591;&#x5757;&#x3002;
&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src1 = cv.imread("letteropen.png")
    img_src2 = cv.imread("letterclose.png")
    print("img_src1_size:", img_src1.shape)
    print("img_src2_size:", img_src2.shape)
    # 2&#x3001;&#x521B;&#x5EFA;&#x6838;&#x7ED3;&#x6784;
    kernel = np.ones((10, 10), np.uint8)
    # 3&#x3001;&#x56FE;&#x50CF;&#x5F00;&#x64CD;&#x4F5C;
    img_src1_tophat = cv.morphologyEx(img_src1, cv.MORPH_TOPHAT, kernel)
    # 4&#x3001;&#x56FE;&#x7247;&#x95ED;&#x64CD;&#x4F5C;
    img_src2_blackhat = cv.morphologyEx(img_src2, cv.MORPH_BLACKHAT, kernel)
    # 5&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8), dpi=100)
    axes[0, 0].imshow(img_src1[:, :, ::-1])
    axes[0, 0].set_title("&#x539F;&#x56FE;1")
    axes[0, 1].imshow(img_src1_tophat[:, :, ::-1])
    axes[0, 1].set_title("&#x539F;&#x56FE;1&#x793C;&#x5E3D;&#x8FD0;&#x7B97;")
    axes[1, 0].imshow(img_src2[:, :, ::-1])
    axes[1, 0].set_title("&#x539F;&#x56FE;2")
    axes[1, 1].imshow(img_src2_blackhat[:, :, ::-1])
    axes[1, 1].set_title("&#x539F;&#x56FE;2&#x9ED1;&#x5E3D;&#x64CD;&#x4F5C;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.17、图像的平滑

&#x793A;&#x4F8B;&#x3001;&#x56FE;&#x50CF;&#x7684;&#x5E73;&#x6ED1;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x5747;&#x503C;&#x6EE4;&#x6CE2;:
  API:cv2.blur(src, ksize, anchor, borderType)
&#x9AD8;&#x65AF;&#x6EE4;&#x6CE2;:
  API:cv2.GaussianBlur(src,ksize,sigmaX,sigmay,borderType)
&#x4E2D;&#x503C;&#x6EE4;&#x6CE2;:
  API:cv2.medianBlur(src, ksize)
&#x53CC;&#x8FB9;&#x6EE4;&#x6CE2;:
  API:cv.bilateralFilter(src, d, sigmaColor,sigmaSpace, dst, borderType)
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_sp_src = cv.imread("dogsp.jpeg")     # &#x5E26;&#x6912;&#x76D0;&#x566A;&#x58F0;&#x539F;&#x56FE;
    img_ga_src = cv.imread("dogGauss.jpeg")  # &#x5E26;&#x9AD8;&#x65AF;&#x566A;&#x58F0;&#x539F;&#x56FE;
    print("img_sp_size:", img_sp_src.shape)
    print("img_ga_size:", img_ga_src.shape)
    # 2&#x3001;&#x5747;&#x503C;&#x6EE4;&#x6CE2;
    img_sp_dst1 = cv.blur(img_sp_src, (5, 5))  # &#x539F;&#x56FE;1&#x7684;&#x5747;&#x503C;&#x6EE4;&#x6CE2;
    img_sp_dst2 = cv.blur(img_ga_src, (5, 5))  # &#x539F;&#x56FE;2&#x7684;&#x5747;&#x503C;&#x6EE4;&#x6CE2;
    img_ga_dst = cv.GaussianBlur(img_ga_src, (3, 3), 1)  # &#x9AD8;&#x65AF;&#x566A;&#x58F0;(&#x9002;&#x5408;&#x9AD8;&#x65AF;&#x566A;&#x58F0;)
    img_me_dst = cv.medianBlur(img_sp_src, 5)  # &#x4E2D;&#x503C;&#x6EE4;&#x6CE2;(&#x9002;&#x5408;&#x6912;&#x76D0;&#x566A;&#x58F0;)
    # 5&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(10, 8), dpi=100)
    axes[0, 0].imshow(img_sp_src[:, :, ::-1])
    axes[0, 0].set_title("&#x5E26;&#x6912;&#x76D0;&#x566A;&#x58F0;&#x539F;&#x56FE;1")
    axes[0, 1].imshow(img_sp_dst1[:, :, ::-1])
    axes[0, 1].set_title("&#x539F;&#x56FE;1&#x7684;&#x5747;&#x503C;&#x6EE4;&#x6CE2;")
    axes[0, 2].imshow(img_me_dst[:, :, ::-1])
    axes[0, 2].set_title("&#x539F;&#x56FE;1&#x7684;&#x4E2D;&#x503C;&#x6EE4;&#x6CE2;")

    axes[1, 0].imshow(img_ga_src[:, :, ::-1])
    axes[1, 0].set_title("&#x5E26;&#x9AD8;&#x65AF;&#x566A;&#x58F0;&#x539F;&#x56FE;2")
    axes[1, 1].imshow(img_sp_dst2[:, :, ::-1])
    axes[1, 1].set_title("&#x539F;&#x56FE;2&#x5747;&#x503C;&#x6EE4;&#x6CE2;")
    axes[1, 2].imshow(img_ga_dst[:, :, ::-1])
    axes[1, 2].set_title("&#x539F;&#x56FE;2&#x9AD8;&#x65AF;&#x6EE4;&#x6CE2;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.18、直方图均衡

&#x793A;&#x4F8B;&#x3001;&#x76F4;&#x65B9;&#x56FE;&#x5747;&#x8861;&#x5316;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4F7F;&#x7528;OpenCV&#x4E2D;&#x7684;&#x65B9;&#x6CD5;&#x7EDF;&#x8BA1;&#x76F4;&#x65B9;&#x56FE;&#xFF0C;&#x5E76;&#x4F7F;&#x7528;matplotlib&#x5C06;&#x5176;&#x7ED8;&#x5236;&#x51FA;&#x6765;
&#x63A9;&#x819C;&#x7684;&#x4F5C;&#x7528;&#x662F;&#x63D0;&#x53D6;&#x611F;&#x5174;&#x8DA3;&#x7684;&#x533A;&#x57DF;(&#x8499;&#x7248;->&#x63A9;&#x819C;)
&#x76F4;&#x65B9;&#x56FE;&#x5747;&#x8861;&#x5316;&#x80FD;&#x63D0;&#x5347;&#x5BF9;&#x6BD4;&#x5EA6;,&#x7528;&#x4E8E;&#x5904;&#x7406;&#x66DD;&#x5149;&#x8FC7;&#x5EA6;&#x6216;&#x66DD;&#x5149;&#x4E0D;&#x8DB3;&#x7684;&#x56FE;&#x7247;
&#x7EDF;&#x8BA1;&#x76F4;&#x65B9;&#x56FE;&#x7684;API&#xFF1A;cv2.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("cat.jpeg", cv.IMREAD_GRAYSCALE)  # &#x4EE5;&#x7070;&#x5EA6;&#x7684;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    # 2&#x3001;&#x7EDF;&#x8BA1;&#x5B8C;&#x6574;&#x76F4;&#x65B9;&#x56FE;(&#x4E0D;&#x5E26;&#x63A9;&#x819C;)
    img_histr = cv.calcHist([img_src], [0], None, [256], [0, 256])
    # 3&#x3001;&#x7EDF;&#x8BA1;&#x5E26;&#x63A9;&#x819C;&#x7684;&#x76F4;&#x65B9;&#x56FE;
    # 3.1&#x3001;&#x521B;&#x5EFA;&#x8499;&#x7248;
    mask = np.zeros(img_src.shape[:2], np.uint8)
    mask[400:650, 200:500] = 1
    # 3.2&#x3001;&#x521B;&#x5EFA;&#x63A9;&#x819C;
    masked_img = cv.bitwise_and(img_src, img_src, mask=mask)  # &#x8499;&#x7248;&#x4E0E;&#x539F;&#x56FE;&#x76F8;&#x4E0E;
    # 3.3&#x3001;&#x539F;&#x56FE;&#x5E26;&#x63A9;&#x819C;&#x7684;&#x76F4;&#x65B9;&#x56FE;
    mask_histr = cv.calcHist([img_src], [0], mask, [256], [0, 256])
    # 4&#x3001;&#x5BF9;&#x539F;&#x56FE;&#x8FDB;&#x884C;&#x76F4;&#x65B9;&#x56FE;&#x5747;&#x8861;&#x5316;
    img_dst = cv.equalizeHist(img_src)
    # 5&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=3, ncols=2, figsize=(10, 6), dpi=100)
    axes[0, 0].imshow(img_src, cmap=plt.cm.gray)
    axes[0, 0].set_title("&#x539F;&#x56FE;")

    axes[0, 1].plot(img_histr)
    axes[0, 1].set_title("&#x539F;&#x56FE;&#x76F4;&#x65B9;&#x56FE;(&#x4E0D;&#x5E26;&#x63A9;&#x819C;)")
    axes[0, 1].grid()  # &#x6DFB;&#x52A0;&#x7F51;&#x683C;

    axes[1, 0].imshow(mask, cmap=plt.cm.gray)
    axes[1, 0].set_title("&#x8499;&#x7248;&#x6570;&#x636E;")

    axes[1, 1].imshow(masked_img, cmap=plt.cm.gray)
    axes[1, 1].set_title("&#x63A9;&#x819C;&#x6570;&#x636E;")

    axes[2, 0].plot(mask_histr)
    axes[2, 0].set_title("&#x5E26;&#x63A9;&#x819C;&#x7684;&#x76F4;&#x65B9;&#x56FE;")
    axes[2, 0].grid()  # &#x6DFB;&#x52A0;&#x7F51;&#x683C;

    axes[2, 1].imshow(img_dst, cmap=plt.cm.gray)
    axes[2, 1].set_title("&#x76F4;&#x65B9;&#x56FE;&#x5747;&#x8861;&#x5316;&#x7ED3;&#x679C;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.19、自适应均衡

&#x793A;&#x4F8B;&#x3001;&#x81EA;&#x9002;&#x5E94;&#x5747;&#x8861;&#x5316;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x76F4;&#x65B9;&#x56FE;&#x5747;&#x8861;&#x5316;&#x662F;&#x5BF9;&#x56FE;&#x50CF;&#x6574;&#x4F53;&#x7684;&#x5747;&#x8861;&#xFF0C;&#x6539;&#x53D8;&#x5168;&#x5C40;&#x5BF9;&#x6BD4;&#x5EA6;&#xFF0C;&#x867D;&#x8BF4;&#x80FD;&#x589E;&#x5F3A;&#x80CC;&#x666F;&#x7EC6;&#x8282;&#xFF0C;&#x4F46;&#x67D0;&#x4E9B;&#x533A;&#x57DF;&#x5BF9;&#x6BD4;&#x5EA6;&#x597D;&#x7684;&#x533A;&#x57DF;&#x5728;&#x76F4;&#x65B9;&#x56FE;&#x5747;&#x8861;&#x5316;&#x540E;&#x6548;&#x679C;&#x4F1A;&#x53D8;&#x5DEE;
cv.createCLAHE(clipLimit, tileGridSize)
  clipLimit: &#x5BF9;&#x6BD4;&#x5EA6;&#x9650;&#x5236;&#xFF0C;&#x9ED8;&#x8BA4;&#x662F;40
  tileGridSize: &#x5206;&#x5757;&#x7684;&#x5927;&#x5C0F;&#xFF0C;&#x9ED8;&#x8BA4;&#x4E3A;8*88&#x2217;8
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("cat.jpeg", cv.IMREAD_GRAYSCALE)  # &#x4EE5;&#x7070;&#x5EA6;&#x7684;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    # 2&#x3001;&#x7EDF;&#x8BA1;&#x539F;&#x56FE;&#x76F4;&#x65B9;&#x56FE;
    img_src_histr = cv.calcHist([img_src], [0], None, [256], [0, 256])
    # 3&#x3001;&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x81EA;&#x9002;&#x5E94;&#x5747;&#x8861;&#x5316;&#x7684;&#x5BF9;&#x8C61;
    clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    # 4&#x3001;&#x81EA;&#x9002;&#x5E94;&#x5747;&#x8861;&#x5316;
    img_dst = clahe.apply(img_src)
    # 5&#x3001;&#x7EDF;&#x8BA1;&#x5747;&#x8861;&#x5316;&#x540E;&#x7684;&#x76F4;&#x65B9;&#x56FE;
    img_dst_histr = cv.calcHist([img_dst], [0], None, [256], [0, 256])
    # 6&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 6), dpi=100)
    axes[0, 0].imshow(img_src, cmap=plt.cm.gray)
    axes[0, 0].set_title("&#x539F;&#x56FE;")

    axes[0, 1].plot(img_src_histr)
    axes[0, 1].set_title("&#x539F;&#x56FE;&#x76F4;&#x65B9;&#x56FE;")
    axes[0, 1].grid()  # &#x6DFB;&#x52A0;&#x7F51;&#x683C;

    axes[1, 0].imshow(img_dst, cmap=plt.cm.gray)
    axes[1, 0].set_title("&#x81EA;&#x9002;&#x5E94;&#x5747;&#x8861;&#x5316;")

    axes[1, 1].plot(img_dst_histr)
    axes[1, 1].set_title("&#x5747;&#x8861;&#x5316;&#x540E;&#x7684;&#x76F4;&#x65B9;&#x56FE;")
    axes[1, 1].grid()  # &#x6DFB;&#x52A0;&#x7F51;&#x683C;
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.20、边缘检测之Sobel

&#x793A;&#x4F8B;&#x3001;&#x8FB9;&#x7F18;&#x68C0;&#x6D4B;&#x4E4B;Sobel
Sobel&#x7B97;&#x5B50;&#xFF1A;&#x7528;&#x4E8E;&#x8FB9;&#x7F18;&#x68C0;&#x6D4B;,&#x7B80;&#x5355;&#x6548;&#x7387;&#x9AD8;,&#x867D;&#x7136;&#x4E0D;&#x5982;Canny&#x68C0;&#x6D4B;&#x51C6;&#x786E;,&#x4F46;&#x5B9E;&#x9645;&#x5F88;&#x591A;&#x573A;&#x5408;,Sobel&#x7B97;&#x5B50;&#x662F;&#x9996;&#x9009;(Sobel&#x7B97;&#x5B50;&#x57FA;&#x4E8E;&#x4E00;&#x9636;&#x5BFC;&#x6570;)
     [ -1 +0 +1 ]         [ -1 -2 -1 ]
Gx = [ -2 +0 +2 ]    Gy = [ +0 +0 +0 ]    Gx&#x7528;&#x4E8E;&#x68C0;&#x6D4B;&#x6C34;&#x5E73;&#x53D8;&#x5316;,Gy&#x7528;&#x4E8E;&#x68C0;&#x6D4B;&#x5782;&#x76F4;&#x53D8;&#x5316;
     [ -1 +0 +1 ]         [ +1 +2 +1 ]
Scharr&#x7B97;&#x5B50;&#xFF1A;&#x5F53;&#x5185;&#x6838;&#x5927;&#x5C0F;&#x4E3A;3&#x65F6;,&#x4EE5;&#x4E0A;Sobel&#x53EF;&#x80FD;&#x4EA7;&#x751F;&#x6BD4;&#x8F83;&#x660E;&#x663E;&#x8BEF;&#x5DEE;,&#x6211;&#x4EEC;&#x4F7F;&#x7528;Scharr&#x7B97;&#x5B50;&#x66FF;&#x4EE3;&#x6765;&#x89E3;&#x51B3;&#x8FD9;&#x4E2A;&#x95EE;&#x9898;(Scharr&#x4EC5;&#x9002;&#x7528;&#x4E8E;&#x5185;&#x6838;&#x5927;&#x5C0F;&#x4E3A;3)
     [ -3  +0 +3  ]         [ -3 -10 -3 ]
Gx = [ -10 +0 +10 ]    Gy = [ +0  +0 +0 ]    Gx&#x7528;&#x4E8E;&#x68C0;&#x6D4B;&#x6C34;&#x5E73;&#x53D8;&#x5316;,Gy&#x7528;&#x4E8E;&#x68C0;&#x6D4B;&#x5782;&#x76F4;&#x53D8;&#x5316;
     [ -3  +0 +3  ]         [ +3 +10 +3 ]
API&#x51FD;&#x6570; cv2.Sobel(src, ddepth, dx, dy, dst, ksize, scale, delta, borderType)
(src:&#x4F20;&#x5165;&#x7684;&#x56FE;&#x50CF;)(ddepth:&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;)(dx&#x548C;dy:&#x6307;&#x6C42;&#x5BFC;&#x7684;&#x9636;&#x6570;,0&#x8868;&#x793A;&#x8FD9;&#x4E2A;&#x65B9;&#x5411;&#x4E0A;&#x6CA1;&#x6709;&#x6C42;&#x5BFC;,&#x53D6;&#x503C;&#x4E3A;0&#x3001;1)
(ksize:&#x662F;Sobel&#x7B97;&#x5B50;&#x7684;&#x5927;&#x5C0F;,&#x5373;&#x5377;&#x79EF;&#x6838;&#x7684;&#x5927;&#x5C0F;,&#x5FC5;&#x987B;&#x4E3A;&#x5947;&#x6570;1&#x3001;3&#x3001;5&#x3001;7,&#x9ED8;&#x8BA4;&#x4E3A;3.&#x6CE8;&#x610F;:&#x5982;&#x679C;ksize=-1,&#x5C31;&#x6F14;&#x53D8;&#x6210;&#x4E3A;3x3&#x7684;Scharr&#x7B97;&#x5B50;)
(scale:&#x7F29;&#x653E;&#x5BFC;&#x6570;&#x7684;&#x6BD4;&#x4F8B;&#x5E38;&#x6570;,&#x9ED8;&#x8BA4;&#x60C5;&#x51B5;&#x4E3A;&#x6CA1;&#x6709;&#x4F38;&#x7F29;&#x7CFB;&#x6570;)(borderType:&#x56FE;&#x50CF;&#x8FB9;&#x754C;&#x7684;&#x6A21;&#x5F0F;,&#x9ED8;&#x8BA4;&#x503C;&#x4E3A;cv2.BORDER_DEFAULT)
->Sobel&#x51FD;&#x6570;&#x6C42;&#x5B8C;&#x5BFC;&#x6570;&#x540E;&#x4F1A;&#x6709;&#x8D1F;&#x503C;,&#x8FD8;&#x6709;&#x4F1A;&#x5927;&#x4E8E;255&#x7684;&#x503C;&#x3002;&#x800C;&#x539F;&#x56FE;&#x50CF;&#x662F;uint8,&#x5373;8&#x4F4D;&#x65E0;&#x7B26;&#x53F7;&#x6570;,&#x6240;&#x4EE5;Sobel&#x5EFA;&#x7ACB;&#x7684;&#x56FE;&#x50CF;&#x4F4D;&#x6570;&#x4E0D;&#x591F;,&#x4F1A;&#x6709;&#x622A;&#x65AD;&#x3002;
->&#x56E0;&#x6B64;&#x8981;&#x4F7F;&#x7528;16&#x4F4D;&#x6709;&#x7B26;&#x53F7;&#x7684;&#x6570;&#x636E;&#x7C7B;&#x578B;,&#x5373;cv2.CV_16S&#x3002;&#x5904;&#x7406;&#x5B8C;&#x56FE;&#x50CF;&#x540E;,&#x518D;&#x4F7F;&#x7528;cv2.convertScaleAbs()&#x51FD;&#x6570;&#x5C06;&#x5176;&#x8F6C;&#x56DE;&#x539F;&#x6765;&#x7684;uint8&#x683C;&#x5F0F;,&#x5426;&#x5219;&#x56FE;&#x50CF;&#x65E0;&#x6CD5;&#x663E;&#x793A;&#x3002;
->Sobel&#x7B97;&#x5B50;&#x662F;&#x5728;&#x4E24;&#x4E2A;&#x65B9;&#x5411;&#x8BA1;&#x7B97;&#x7684;,&#x6700;&#x540E;&#x8FD8;&#x9700;&#x8981;&#x7528;cv2.addWeighted()&#x51FD;&#x6570;&#x5C06;&#x5176;&#x7EC4;&#x5408;&#x8D77;&#x6765;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("horse.jpg", cv.IMREAD_GRAYSCALE)  # &#x4EE5;&#x7070;&#x5EA6;&#x7684;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    # 2&#x3001;&#x8BA1;&#x7B97;Sobel&#x5377;&#x79EF;&#x7ED3;&#x679C;
    sobel_x = cv.Sobel(img_src, cv.CV_16S, 1, 0)  # Scharr: cv.Sobel(img_src, cv.CV_16S, 1, 0, ksize=-1)
    sobel_y = cv.Sobel(img_src, cv.CV_16S, 0, 1)  # Scharr: cv.Sobel(img_src, cv.CV_16S, 0, 1, ksize=-1)
    # 3&#x3001;&#x5C06;&#x6570;&#x636E;&#x8FDB;&#x884C;&#x8F6C;&#x6362;
    scaleAbs_x = cv.convertScaleAbs(sobel_x)
    scaleAbs_y = cv.convertScaleAbs(sobel_y)
    # 4&#x3001;&#x7ED3;&#x679C;&#x5408;&#x6210;
    result = cv.addWeighted(scaleAbs_x, 0.5, scaleAbs_y, 0.5, 0)
    # 5&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    plt.subplot(1, 2, 1), plt.imshow(img_src, cmap=plt.cm.gray), plt.title("&#x539F;&#x56FE;")
    plt.subplot(1, 2, 2), plt.imshow(result, cmap=plt.cm.gray), plt.title("Sobel&#x6EE4;&#x6CE2;&#x540E;&#x7ED3;&#x679C;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.21、边缘检测之Laplacian

&#x793A;&#x4F8B;&#x3001;&#x8FB9;&#x7F18;&#x68C0;&#x6D4B;&#x4E4B;Laplacian(&#x62C9;&#x666E;&#x62C9;&#x65AF;)
Laplacian&#x7B97;&#x5B50;:Laplacian&#x662F;&#x5229;&#x7528;&#x4E8C;&#x9636;&#x5BFC;&#x6570;&#x6765;&#x68C0;&#x6D4B;&#x8FB9;&#x7F18;
         [ +0 +1 +0 ]
kernel = [ +1 -4 +1 ]
         [ +0 +1 +0 ]
API&#x51FD;&#x6570;:cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
Src:&#x9700;&#x8981;&#x5904;&#x7406;&#x7684;&#x56FE;&#x50CF;.

Ddepth:&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;,-1&#x8868;&#x793A;&#x91C7;&#x7528;&#x7684;&#x662F;&#x539F;&#x56FE;&#x50CF;&#x76F8;&#x540C;&#x7684;&#x6DF1;&#x5EA6;,&#x76EE;&#x6807;&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;&#x5FC5;&#x987B;&#x5927;&#x4E8E;&#x7B49;&#x4E8E;&#x539F;&#x56FE;&#x50CF;&#x7684;&#x6DF1;&#x5EA6;.

ksize:&#x7B97;&#x5B50;&#x7684;&#x5927;&#x5C0F;,&#x5373;&#x5377;&#x79EF;&#x6838;&#x7684;&#x5927;&#x5C0F;,&#x5FC5;&#x987B;&#x4E3A;1,3,5,7.

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("horse.jpg", cv.IMREAD_GRAYSCALE)  # &#x4EE5;&#x7070;&#x5EA6;&#x7684;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    # 2&#x3001;laplacian
    lap_dst = cv.Laplacian(img_src, cv.CV_16S)
    img_dst = cv.convertScaleAbs(lap_dst)
    # 3&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    plt.subplot(1, 2, 1), plt.imshow(img_src, cmap=plt.cm.gray), plt.title("&#x539F;&#x56FE;")
    plt.subplot(1, 2, 2), plt.imshow(img_dst, cmap=plt.cm.gray), plt.title("Laplacian&#x6EE4;&#x6CE2;&#x540E;&#x7ED3;&#x679C;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

P1.22、边缘检测之Canny

&#x793A;&#x4F8B;&#x3001;&#x8FB9;&#x7F18;&#x68C0;&#x6D4B;Canny
Canny&#x8FB9;&#x7F18;&#x68C0;&#x6D4B;&#x7B97;&#x6CD5;&#x662F;&#x7531;4&#x6B65;&#x6784;&#x6210;,&#x5206;&#x522B;&#x4ECB;&#x7ECD;&#x5982;&#x4E0B;&#xFF1A;
&#x7B2C;&#x4E00;&#x6B65;&#xFF1A;&#x566A;&#x58F0;&#x53BB;&#x9664;(&#x7531;&#x4E8E;&#x8FB9;&#x7F18;&#x68C0;&#x6D4B;&#x5F88;&#x5BB9;&#x6613;&#x53D7;&#x5230;&#x566A;&#x58F0;&#x7684;&#x5F71;&#x54CD;,&#x6240;&#x4EE5;&#x9996;&#x5148;&#x4F7F;&#x7528;$5*5$&#x9AD8;&#x65AF;&#x6EE4;&#x6CE2;&#x5668;&#x53BB;&#x9664;&#x566A;&#x58F0;)
&#x7B2C;&#x4E8C;&#x6B65;&#xFF1A;&#x8BA1;&#x7B97;&#x56FE;&#x50CF;&#x68AF;&#x5EA6;(&#x5BF9;&#x5E73;&#x6ED1;&#x540E;&#x7684;&#x56FE;&#x50CF;&#x4F7F;&#x7528;Sobel&#x7B97;&#x5B50;&#x8BA1;&#x7B97;&#x6C34;&#x5E73;&#x65B9;&#x5411;&#x548C;&#x7AD6;&#x76F4;&#x65B9;&#x5411;&#x7684;&#x4E00;&#x9636;&#x5BFC;&#x6570;(Gx&#x548C;Gy),&#x68AF;&#x5EA6;&#x65B9;&#x5411;&#x5206;&#x4E3A;&#x56DB;&#x7C7B;&#xFF1A;&#x5782;&#x76F4;,&#x6C34;&#x5E73;,&#x548C;&#x4E24;&#x4E2A;&#x5BF9;&#x89D2;&#x7EBF;&#x65B9;&#x5411;)
&#x7B2C;&#x4E09;&#x6B65;&#xFF1A;&#x975E;&#x6781;&#x5927;&#x503C;&#x6291;&#x5236;(&#x5728;&#x83B7;&#x5F97;&#x68AF;&#x5EA6;&#x7684;&#x65B9;&#x5411;&#x548C;&#x5927;&#x5C0F;&#x4E4B;&#x540E;,&#x5BF9;&#x6574;&#x5E45;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x626B;&#x63CF;,&#x53BB;&#x9664;&#x90A3;&#x4E9B;&#x975E;&#x8FB9;&#x754C;&#x4E0A;&#x7684;&#x70B9;&#x3002;&#x5BF9;&#x6BCF;&#x4E00;&#x4E2A;&#x50CF;&#x7D20;&#x8FDB;&#x884C;&#x68C0;&#x67E5;,&#x770B;&#x8FD9;&#x4E2A;&#x70B9;&#x7684;&#x68AF;&#x5EA6;&#x662F;&#x4E0D;&#x662F;&#x5468;&#x56F4;&#x5177;&#x6709;&#x76F8;&#x540C;&#x68AF;&#x5EA6;&#x65B9;&#x5411;&#x7684;&#x70B9;&#x4E2D;&#x6700;&#x5927;&#x7684;)
&#x7B2C;&#x56DB;&#x6B65;&#xFF1A;&#x6EDE;&#x540E;&#x9608;&#x503C;(&#x73B0;&#x5728;&#x8981;&#x786E;&#x5B9A;&#x771F;&#x6B63;&#x7684;&#x8FB9;&#x754C;&#x3002;&#x6211;&#x4EEC;&#x8BBE;&#x7F6E;&#x4E24;&#x4E2A;&#x9608;&#x503C;&#xFF1A;minVal&#x548C;maxVal&#x3002;&#x5F53;&#x56FE;&#x50CF;&#x7684;&#x7070;&#x5EA6;&#x68AF;&#x5EA6;&#x9AD8;&#x4E8E;maxVal&#x65F6;&#x88AB;&#x8BA4;&#x4E3A;&#x662F;&#x771F;&#x7684;&#x8FB9;&#x754C;,
      &#x4F4E;&#x4E8E;minVal&#x7684;&#x8FB9;&#x754C;&#x4F1A;&#x88AB;&#x629B;&#x5F03;&#x3002;&#x5982;&#x679C;&#x4ECB;&#x4E8E;&#x4E24;&#x8005;&#x4E4B;&#x95F4;&#x7684;&#x8BDD;,&#x5C31;&#x8981;&#x770B;&#x8FD9;&#x4E2A;&#x70B9;&#x662F;&#x5426;&#x4E0E;&#x67D0;&#x4E2A;&#x88AB;&#x786E;&#x5B9A;&#x4E3A;&#x771F;&#x6B63;&#x7684;&#x8FB9;&#x754C;&#x70B9;&#x76F8;&#x8FDE;,&#x5982;&#x679C;&#x662F;&#x5C31;&#x8BA4;&#x4E3A;&#x5B83;&#x4E5F;&#x662F;&#x8FB9;&#x754C;&#x70B9;,&#x5982;&#x679C;&#x4E0D;&#x662F;&#x5C31;&#x629B;&#x5F03;&#xFF09;
API&#x51FD;&#x6570;:cv2.Canny(image, threshold1, threshold2)
      image:&#x7070;&#x5EA6;&#x56FE;&#x3002;
      threshold1: minval,&#x8F83;&#x5C0F;&#x7684;&#x9608;&#x503C;&#x5C06;&#x95F4;&#x65AD;&#x7684;&#x8FB9;&#x7F18;&#x8FDE;&#x63A5;&#x8D77;&#x6765;&#x3002;
      threshold2: maxval,&#x8F83;&#x5927;&#x7684;&#x9608;&#x503C;&#x68C0;&#x6D4B;&#x56FE;&#x50CF;&#x4E2D;&#x660E;&#x663E;&#x7684;&#x8FB9;&#x7F18;&#x3002;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("horse.jpg", cv.IMREAD_GRAYSCALE)  # &#x4EE5;&#x7070;&#x5EA6;&#x7684;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x56FE;&#x7247;
    # 2&#x3001;Canny&#x68C0;&#x6D4B;
    img_dst = cv.Canny(img_src, 0, 100)
    # 3&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    plt.subplot(1, 2, 1), plt.imshow(img_src, cmap=plt.cm.gray), plt.title("&#x539F;&#x56FE;")
    plt.subplot(1, 2, 2), plt.imshow(img_dst, cmap=plt.cm.gray), plt.title("Canny&#x540E;&#x7684;&#x7ED3;&#x679C;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

常见算子的比较与总结:

38、OpenCV之C++教程

P1.23、模板匹配< 重点 >

所谓的模板匹配,就是在给定的图片中查找和模板最相似的区域,该算法的输入包括模板和图片,整个任务的思路就是按照滑窗的思路不断的移动模板图片,计算其与图像中对应区域的匹配度,最终将匹配度最高的区域选择为最终的结果。

实现流程:

  • 准备两幅图像: 1.原图像(I):在这幅图中,找到与模板相匹配的区域 2.模板(T):与原图像进行比对的图像块

38、OpenCV之C++教程
  • 滑动模板图像和原图像进行比对:

38、OpenCV之C++教程

将模板块每次移动一个像素 (从左往右,从上往下),在每一个位置,都计算与模板图像的相似程度。

  • 对于每一个位置将计算的相似结果保存在结果矩阵(R)中.如果输入图像的大小(WxH)且模板图像的大小(wxh),则输出矩阵R的大小为(W-w+1,H-h+1)将R显示为图像,如下图所示:

38、OpenCV之C++教程
  • 获得上述图像后,查找最大值所在的位置,那么该位置对应的区域就被认为是最匹配的。对应的区域就是以该点为顶点,长宽和模板图像一样大小的矩阵。

API:

res = cv.matchTemplate(img,template,method)

参数:

  • img: 要进行模板匹配的图像
  • Template :模板
  • method:实现模板匹配的算法,主要有:
  • 平方差匹配(CV_TM_SQDIFF):利用模板与图像之间的平方差进行匹配,最好的匹配是0,匹配越差,匹配的值越大。
  • 相关匹配(CV_TM_CCORR):利用模板与图像间的乘法进行匹配,数值越大表示匹配程度较高,越小表示匹配效果差。
  • 利用相关系数匹配(CV_TM_CCOEFF):利用模板与图像间的相关系数匹配,1表示完美的匹配,-1表示最差的匹配。

完成匹配后,使用cv.minMaxLoc()方法查找最大值所在的位置即可。如果使用平方差作为比较方法,则最小值位置是最佳匹配位置。

在该案例中,载入要搜索的图像和模板,图像如下所示:

38、OpenCV之C++教程

模板如下所示:

38、OpenCV之C++教程

用matchTemplate实现模板匹配,使用minMaxLoc定位最匹配的区域并用矩形标注最匹配的区域。

&#x793A;&#x4F8B;&#x3001;&#x6A21;&#x677F;&#x5339;&#x914D;(1)
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("wulin.jpeg", cv.IMREAD_UNCHANGED)  # &#x8BFB;&#x53D6;&#x539F;&#x56FE;
    img_tmp = cv.imread("wulin2.jpeg", cv.IMREAD_UNCHANGED)  # &#x8BFB;&#x53D6;&#x6A21;&#x677F;
    h, w = img_tmp.shape[:2]
    # 2 &#x6A21;&#x677F;&#x5339;&#x914D;
    # 2.1 &#x6A21;&#x677F;&#x5339;&#x914D;
    res = cv.matchTemplate(img_src, img_tmp, cv.TM_CCORR)
    # 2.2 &#x8FD4;&#x56DE;&#x56FE;&#x50CF;&#x4E2D;&#x6700;&#x5339;&#x914D;&#x7684;&#x4F4D;&#x7F6E;&#xFF0C;&#x786E;&#x5B9A;&#x5DE6;&#x4E0A;&#x89D2;&#x7684;&#x5750;&#x6807;&#xFF0C;&#x5E76;&#x5C06;&#x5339;&#x914D;&#x4F4D;&#x7F6E;&#x7ED8;&#x5236;&#x5728;&#x56FE;&#x50CF;&#x4E0A;
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
    # &#x4F7F;&#x7528;&#x5E73;&#x65B9;&#x5DEE;&#x65F6;&#x6700;&#x5C0F;&#x503C;&#x4E3A;&#x6700;&#x4F73;&#x5339;&#x914D;&#x4F4D;&#x7F6E;
    # top_left = min_loc
    top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv.rectangle(img_src, top_left, bottom_right, (0, 255, 0), 2)
    # 3&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    plt.subplot(1, 2, 1), plt.imshow(res, cmap=plt.cm.gray), plt.title("&#x6A21;&#x677F;&#x5339;&#x914D;&#x7ED3;&#x679C;")  # &#x7070;&#x5EA6;&#x56FE;&#x4E0D;&#x9700;&#x8981;&#x4EA4;&#x6362;&#x901A;&#x9053;,&#x56E0;&#x4E3A;&#x53EA;&#x6709;&#x4E00;&#x4E2A;&#x901A;&#x9053;
    plt.subplot(1, 2, 2), plt.imshow(img_src[:, :, ::-1]), plt.title("&#x7ED3;&#x679C;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程
&#x6587;&#x4EF6;&#x4E00;&#xFF1A;myutils
import cv2
&#x51FD;&#x6570;1:
def sort_contours(cnts, method="left-to-right"):
    reverse = False
    i = 0
    if method == "right-to-left" or method == "bottom-to-top":
        reverse = True
    if method == "top-to-bottom" or method == "bottom-to-top":
        i = 1
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]  # &#x7528;&#x4E00;&#x4E2A;&#x6700;&#x5C0F;&#x7684;&#x77E9;&#x5F62;&#xFF0C;&#x628A;&#x627E;&#x5230;&#x7684;&#x5F62;&#x72B6;&#x5305;&#x8D77;&#x6765;x,y,h,w
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes), key=lambda b: b[1][i], reverse=reverse))
    return cnts, boundingBoxes
&#x51FD;&#x6570;2:
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    resized = cv2.resize(image, dim, interpolation=inter)
    return resized
&#x6587;&#x4EF6;&#x4E8C;&#xFF1A;main.py
&#x7A0B;&#x5E8F;&#x8FD0;&#x884C;&#x65B9;&#x6CD5;&#xFF1A;python main.py -i credit_card_01.png -t ocr_a_reference.png
from imutils import contours
import numpy as np
import argparse
import cv2
import myutils
&#x8BBE;&#x7F6E;&#x53C2;&#x6570;
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to input image")
ap.add_argument("-t", "--template", required=True, help="path to template OCR-A image")
args = vars(ap.parse_args())

&#x6307;&#x5B9A;&#x4FE1;&#x7528;&#x5361;&#x7C7B;&#x578B;
FIRST_NUMBER = {
    "3": "American Express",
    "4": "Visa",
    "5": "MasterCard",
    "6": "Discover Card"
}

&#x7ED8;&#x56FE;&#x5C55;&#x793A;
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    return

&#x8BFB;&#x53D6;&#x4E00;&#x4E2A;&#x6A21;&#x677F;&#x56FE;&#x50CF;
img = cv2.imread(args["template"])
cv_show('img', img)
&#x7070;&#x5EA6;&#x56FE;
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref', ref)
&#x4E8C;&#x503C;&#x56FE;&#x50CF;
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]  # &#x8FD4;&#x56DE;&#x7B2C;&#x4E8C;&#x4E2A;&#x53C2;&#x6570;
cv_show('ref', ref)

&#x8BA1;&#x7B97;&#x8F6E;&#x5ED3;
cv2.findContours()&#x51FD;&#x6570;&#x63A5;&#x53D7;&#x7684;&#x53C2;&#x6570;&#x4E3A;&#x4E8C;&#x503C;&#x56FE;&#xFF0C;&#x5373;&#x9ED1;&#x767D;&#x7684;&#xFF08;&#x4E0D;&#x662F;&#x7070;&#x5EA6;&#x56FE;&#xFF09;,cv2.RETR_EXTERNAL&#x53EA;&#x68C0;&#x6D4B;&#x5916;&#x8F6E;&#x5ED3;&#xFF0C;cv2.CHAIN_APPROX_SIMPLE&#x53EA;&#x4FDD;&#x7559;&#x7EC8;&#x70B9;&#x5750;&#x6807;
&#x8FD4;&#x56DE;&#x7684;list&#x4E2D;&#x6BCF;&#x4E2A;&#x5143;&#x7D20;&#x90FD;&#x662F;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4E00;&#x4E2A;&#x8F6E;&#x5ED3;
ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3)
cv_show('img', img)

print(np.array(refCnts).shape)
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]  # &#x6392;&#x5E8F;&#xFF0C;&#x4ECE;&#x5DE6;&#x5230;&#x53F3;&#xFF0C;&#x4ECE;&#x4E0A;&#x5230;&#x4E0B;
digits = {}

&#x904D;&#x5386;&#x6BCF;&#x4E00;&#x4E2A;&#x8F6E;&#x5ED3;
for (i, c) in enumerate(refCnts):
    # &#x8BA1;&#x7B97;&#x5916;&#x63A5;&#x77E9;&#x5F62;&#x5E76;&#x4E14;resize&#x6210;&#x5408;&#x9002;&#x5927;&#x5C0F;
    (x, y, w, h) = cv2.boundingRect(c)
    roi = ref[y:y + h, x:x + w]
    roi = cv2.resize(roi, (57, 88))
    # &#x6BCF;&#x4E00;&#x4E2A;&#x6570;&#x5B57;&#x5BF9;&#x5E94;&#x6BCF;&#x4E00;&#x4E2A;&#x6A21;&#x677F;
    digits[i] = roi

&#x521D;&#x59CB;&#x5316;&#x5377;&#x79EF;&#x6838;
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

&#x8BFB;&#x53D6;&#x8F93;&#x5165;&#x56FE;&#x50CF;&#xFF0C;&#x9884;&#x5904;&#x7406;
image = cv2.imread(args["image"])
cv_show('image', image)
image = myutils.resize(image, width=300)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv_show('gray', gray)

&#x793C;&#x5E3D;&#x64CD;&#x4F5C;&#xFF0C;&#x7A81;&#x51FA;&#x66F4;&#x660E;&#x4EAE;&#x7684;&#x533A;&#x57DF;
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show('tophat', tophat)
#
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)  # ksize=-1&#x76F8;&#x5F53;&#x4E8E;&#x7528;3*3&#x7684;

gradX = np.absolute(gradX)
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")

print(np.array(gradX).shape)
cv_show('gradX', gradX)

&#x901A;&#x8FC7;&#x95ED;&#x64CD;&#x4F5C;&#xFF08;&#x5148;&#x81A8;&#x80C0;&#xFF0C;&#x518D;&#x8150;&#x8680;&#xFF09;&#x5C06;&#x6570;&#x5B57;&#x8FDE;&#x5728;&#x4E00;&#x8D77;
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv_show('gradX', gradX)
THRESH_OTSU&#x4F1A;&#x81EA;&#x52A8;&#x5BFB;&#x627E;&#x5408;&#x9002;&#x7684;&#x9608;&#x503C;&#xFF0C;&#x9002;&#x5408;&#x53CC;&#x5CF0;&#xFF0C;&#x9700;&#x628A;&#x9608;&#x503C;&#x53C2;&#x6570;&#x8BBE;&#x7F6E;&#x4E3A;0
thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('thresh', thresh)

&#x518D;&#x6765;&#x4E00;&#x4E2A;&#x95ED;&#x64CD;&#x4F5C;
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)  # &#x518D;&#x6765;&#x4E00;&#x4E2A;&#x95ED;&#x64CD;&#x4F5C;
cv_show('thresh', thresh)

&#x8BA1;&#x7B97;&#x8F6E;&#x5ED3;
thresh_, threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
cv_show('img', cur_img)
locs = []

&#x904D;&#x5386;&#x8F6E;&#x5ED3;
for (i, c) in enumerate(cnts):
    # &#x8BA1;&#x7B97;&#x77E9;&#x5F62;
    (x, y, w, h) = cv2.boundingRect(c)
    ar = w / float(h)
    # &#x9009;&#x62E9;&#x5408;&#x9002;&#x7684;&#x533A;&#x57DF;&#xFF0C;&#x6839;&#x636E;&#x5B9E;&#x9645;&#x4EFB;&#x52A1;&#x6765;&#xFF0C;&#x8FD9;&#x91CC;&#x7684;&#x57FA;&#x672C;&#x90FD;&#x662F;&#x56DB;&#x4E2A;&#x6570;&#x5B57;&#x4E00;&#x7EC4;
    if ar > 2.5 and ar < 4.0:
        if (w > 40 and w < 55) and (h > 10 and h < 20):
            # &#x7B26;&#x5408;&#x7684;&#x7559;&#x4E0B;&#x6765;
            locs.append((x, y, w, h))

&#x5C06;&#x7B26;&#x5408;&#x7684;&#x8F6E;&#x5ED3;&#x4ECE;&#x5DE6;&#x5230;&#x53F3;&#x6392;&#x5E8F;
locs = sorted(locs, key=lambda x: x[0])
output = []

&#x904D;&#x5386;&#x6BCF;&#x4E00;&#x4E2A;&#x8F6E;&#x5ED3;&#x4E2D;&#x7684;&#x6570;&#x5B57;
for (i, (gX, gY, gW, gH)) in enumerate(locs):
    # initialize the list of group digits
    groupOutput = []
    # &#x6839;&#x636E;&#x5750;&#x6807;&#x63D0;&#x53D6;&#x6BCF;&#x4E00;&#x4E2A;&#x7EC4;
    group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
    cv_show('group', group)
    # &#x9884;&#x5904;&#x7406;
    group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    cv_show('group', group)
    # &#x8BA1;&#x7B97;&#x6BCF;&#x4E00;&#x7EC4;&#x7684;&#x8F6E;&#x5ED3;
    group_, digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    digitCnts = contours.sort_contours(digitCnts, method="left-to-right")[0]
    # &#x8BA1;&#x7B97;&#x6BCF;&#x4E00;&#x7EC4;&#x4E2D;&#x7684;&#x6BCF;&#x4E00;&#x4E2A;&#x6570;&#x503C;
    for c in digitCnts:
        # &#x627E;&#x5230;&#x5F53;&#x524D;&#x6570;&#x503C;&#x7684;&#x8F6E;&#x5ED3;&#xFF0C;resize&#x6210;&#x5408;&#x9002;&#x7684;&#x7684;&#x5927;&#x5C0F;
        (x, y, w, h) = cv2.boundingRect(c)
        roi = group[y:y + h, x:x + w]
        roi = cv2.resize(roi, (57, 88))
        cv_show('roi', roi)
        # &#x8BA1;&#x7B97;&#x5339;&#x914D;&#x5F97;&#x5206;
        scores = []
        # &#x5728;&#x6A21;&#x677F;&#x4E2D;&#x8BA1;&#x7B97;&#x6BCF;&#x4E00;&#x4E2A;&#x5F97;&#x5206;
        for (digit, digitROI) in digits.items():
            # &#x6A21;&#x677F;&#x5339;&#x914D;
            result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)
            (_, score, _, _) = cv2.minMaxLoc(result)
            scores.append(score)
        # &#x5F97;&#x5230;&#x6700;&#x5408;&#x9002;&#x7684;&#x6570;&#x5B57;
        groupOutput.append(str(np.argmax(scores)))
    # &#x753B;&#x51FA;&#x6765;
    cv2.rectangle(image, (gX - 5, gY - 5), (gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)
    cv2.putText(image, "".join(groupOutput), (gX, gY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
    # &#x5F97;&#x5230;&#x7ED3;&#x679C;
    output.extend(groupOutput)

&#x6253;&#x5370;&#x7ED3;&#x679C;
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)

38、OpenCV之C++教程

P1.24、霍夫变换< 重点 >

霍夫变换常用来提取图像中的直线和圆等几何形状,如下图所示:

38、OpenCV之C++教程

在OpenCV中做霍夫线检测是使用的API是:

cv.HoughLines(img, rho, theta, threshold)

参数:

  • img: 检测的图像,要求是二值化的图像,所以在调用霍夫变换之前首先要进行二值化,或者进行Canny边缘检测
  • rho、theta: \rhoρ 和\thetaθ的精确度
  • threshold: 阈值,只有累加器中的值高于该阈值时才被认为是直线。 霍夫线检测的整个流程如下图所示,这是在stackflow上一个关于霍夫线变换的解释:

38、OpenCV之C++教程

霍夫线检测示例:检测下述图像中的直线:

38、OpenCV之C++教程
&#x793A;&#x4F8B;&#x3001;&#x970D;&#x592B;&#x7EBF;&#x68C0;&#x6D4B;(1)
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("rili.jpg", cv.IMREAD_UNCHANGED)
    img_gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY)
    img_edges = cv.Canny(img_gray, 50, 150)
    # 2&#x3001;&#x970D;&#x592B;&#x76F4;&#x7EBF;&#x53D8;&#x6362;
    lines = cv.HoughLines(img_edges, 0.8, np.pi/180, 160)
    for line in lines:
        rho, theta = line[0]
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a * rho
        y0 = b * rho
        x1 = int(x0 + 1000 * (-b))
        y1 = int(y0 + 1000 * a)
        x2 = int(x0 - 1000 * (-b))
        y2 = int(y0 - 1000 * a)
        cv.line(img_src, (x1, y1), (x2, y2), (0, 255, 0))
    # 3&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    plt.subplot(2, 2, 1), plt.imshow(img_gray, cmap=plt.cm.gray), plt.title("&#x539F;&#x56FE;&#x7684;&#x7070;&#x5EA6;&#x56FE;")
    plt.subplot(2, 2, 2), plt.imshow(img_edges, cmap=plt.cm.gray), plt.title("&#x7070;&#x5EA6;&#x56FE;&#x7684;Canny&#x68C0;&#x6D4B;")
    #plt.subplot(2, 2, 3), plt.imshow(lines), plt.title("&#x7070;")  #&#x663E;&#x793A;&#x970D;&#x592B;&#x7A7A;&#x95F4;
    plt.subplot(2, 2, 3), plt.imshow(img_src[:, :, ::-1]), plt.title("&#x970D;&#x592B;&#x7EBF;&#x68C0;&#x6D4B;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程
  1. 原理 圆的表示式是:(x-a)^2+(y-b)^2=​​r,其中a和b表示圆心坐标,r表示圆半径,因此标准的霍夫圆检测就是在这三个参数组成的三维空间累加器上进行圆形检测,此时效率就会很低,所以OpenCV中使用 霍夫梯度法进行圆形的检测。 霍夫梯度法将霍夫圆检测范围两个阶段,第一阶段检测圆心,第二阶段利用圆心推导出圆半径。
  2. 圆心检测的原理:圆心是圆周法线的交汇处,设置一个阈值,在某点的相交的直线的条数大于这个阈值就认为该交汇点为圆心。
  3. 圆半径确定原理:圆心到圆周上的距离(半径)是相同的,确定一个阈值,只要相同距离的数量大于该阈值,就认为该距离是该圆心的半径。 原则上霍夫变换可以检测任何形状,但复杂的形状需要的参数就多,霍夫空间的维数就多,因此在程序实现上所需的内存空间以及运行效率上都不利于把标准霍夫变换应用于实际复杂图形的检测中。霍夫梯度法是霍夫变换的改进,它的目的是减小霍夫空间的维度,提高效率。
  4. API 在OpenCV中检测图像中的圆环使用的是API是:
circles = cv.HoughCircles(image, method, dp, minDist, param1=100, param2=100, minRadius=0,maxRadius=0 )

参数:
– image:输入图像,应输入灰度图像
– method:使用霍夫变换圆检测的算法,它的参数是CV_HOUGH_GRADIENT
– dp:霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半,以此类推
– minDist为圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心
– param1:边缘检测时使用Canny算子的高阈值,低阈值是高阈值的一半。
– param2:检测圆心和确定半径时所共有的阈值
– minRadius和maxRadius为所检测到的圆半径的最小值和最大值 返回:circles:输出圆向量,包括三个浮点型的元素——圆心横坐标,圆心纵坐标和圆半径

实现:由于霍夫圆检测对噪声比较敏感,所以首先对图像进行中值滤波

&#x793A;&#x4F8B;&#x3001;&#x970D;&#x592B;&#x5706;&#x68C0;&#x6D4B;(2)
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("star.jpeg", cv.IMREAD_UNCHANGED)
    img_gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY)
    # 2&#x3001;&#x8FDB;&#x884C;&#x4E2D;&#x503C;&#x6A21;&#x7CCA;&#xFF0C;&#x53BB;&#x566A;&#x70B9;
    img_me = cv.medianBlur(img_gray, 7)
    # 3&#x3001;&#x970D;&#x592B;&#x5706;&#x68C0;&#x6D4B;
    circles = cv.HoughCircles(img_me, cv.HOUGH_GRADIENT, 1, 200, param1=100, param2=30, minRadius=0, maxRadius=100)
    # 4&#x3001;&#x5C06;&#x68C0;&#x6D4B;&#x7ED3;&#x679C;&#x7ED8;&#x5236;&#x5728;&#x56FE;&#x50CF;&#x4E0A;
    for i in circles[0, :]:  # &#x904D;&#x5386;&#x77E9;&#x9635;&#x6BCF;&#x4E00;&#x884C;&#x7684;&#x6570;&#x636E;
        # &#x7ED8;&#x5236;&#x5706;&#x5F62;
        cv.circle(img_src, (i[0], i[1]), i[2], (0, 255, 0), 2)
        # &#x7ED8;&#x5236;&#x5706;&#x5FC3;
        cv.circle(img_src, (i[0], i[1]), 2, (0, 0, 255), 3)
    # 3&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    plt.subplot(1, 2, 1), plt.imshow(img_me, cmap=plt.cm.gray), plt.title("&#x7070;&#x5EA6;&#x56FE;&#x7684;&#x4E2D;&#x503C;")
    plt.subplot(1, 2, 2), plt.imshow(img_src[:, :, ::-1]), plt.title("&#x970D;&#x592B;&#x5706;&#x68C0;&#x6D4B;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程

P1.25、傅里叶变换< 重点 >

傅里叶变换到频域:
高频:变化剧烈的灰度分量,例如边界。
低频:变化缓慢的灰度分量,例如一片大海。
频域滤波:
低通滤波器:只保留低频,会使图像变模糊。
高通滤波器:只保留高频,会使得图像的细节增强。
OpenCV中的API:
cv2.dft() : 傅里叶正变换,输入图像需要先转换为np.float32格式。
cv2.idft() : 傅里叶反变换,返回的结果是复数形式,需要转换图像格式。

&#x793A;&#x4F8B;&#x3001;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;(1)
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1 &#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img_src = cv.imread('lena.jpg', cv.IMREAD_GRAYSCALE)  # &#x4EE5;&#x7070;&#x5EA6;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x539F;&#x56FE;
    img_float32 = np.float32(img_src)  # &#x8F6C;&#x6362;&#x6210;float32&#x7684;&#x683C;&#x5F0F;
    # 2&#x3001;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;
    dft = cv.dft(img_float32, flags=cv.DFT_COMPLEX_OUTPUT)  # &#x6B63;&#x5411;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;
    dft_shift = np.fft.fftshift(dft)  # &#x79FB;&#x76F8;
    # 3&#x3001;&#x5F97;&#x5230;&#x7070;&#x5EA6;&#x56FE;&#x80FD;&#x8868;&#x793A;&#x7684;&#x683C;&#x5F0F;
    img_magnitude = 20*np.log(cv.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 0]))  # magnitude &#x8BA1;&#x7B97;&#x77E9;&#x9635;&#x7EF4;&#x5EA6;&#x7684;&#x5E73;&#x65B9;&#x6839;
    # 4&#x3001;&#x663E;&#x793A;&#x53D8;&#x6362;&#x7ED3;&#x679C;(&#x4E2D;&#x95F4;&#x662F;&#x4F4E;&#x9891;,&#x8D8A;&#x5F80;&#x5916;&#x9891;&#x7387;&#x8D8A;&#x9AD8;)
    plt.subplot(121), plt.imshow(img_src, cmap="gray")  # &#x6E90;&#x56FE;&#x50CF;
    plt.subplot(122), plt.imshow(img_magnitude, cmap="gray")  # &#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;&#x7ED3;&#x679C;
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程
&#x793A;&#x4F8B;&#x3001;&#x4F4E;&#x901A;&#x6EE4;&#x6CE2;&#x5668;&#x7684;&#x7B80;&#x5355;&#x5B9E;&#x73B0;(2)
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1 &#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img_src = cv.imread('lena.jpg', cv.IMREAD_GRAYSCALE)  # &#x4EE5;&#x7070;&#x5EA6;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x539F;&#x56FE;
    rows, cols = img_src.shape  # &#x56FE;&#x50CF;&#x5C3A;&#x5BF8;
    crow, ccol = int(rows/2), int(cols/2)  # &#x4E2D;&#x5FC3;&#x4F4D;&#x7F6E;
    img_float32 = np.float32(img_src)  # &#x8F6C;&#x6362;&#x6210;float32&#x7684;&#x683C;&#x5F0F;
    # 2&#x3001;&#x79BB;&#x6563;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;
    dft = cv.dft(img_float32, flags=cv.DFT_COMPLEX_OUTPUT)  # &#x6B63;&#x5411;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;
    # 3&#x3001;shift&#x53D8;&#x6362;
    dft_shift = np.fft.fftshift(dft)  # &#x5C06;&#x96F6;&#x9891;&#x70B9;&#x79FB;&#x5230;&#x9891;&#x8C31;&#x7684;&#x4E2D;&#x95F4;(shift&#x540E;,&#x4E2D;&#x95F4;&#x4E3A;&#x4F4E;&#x9891;&#x90E8;&#x5206;)
    # 4&#x3001;&#x521B;&#x5EFA;&#x63A9;&#x819C;,&#x4FDD;&#x7559;&#x4E2D;&#x5FC3;&#x7684;&#x63A9;&#x819C;
    mask = np.zeros((rows, cols, 2), np.uint8)  # &#x56E0;&#x4E3A;&#x8F93;&#x51FA;&#x662F;&#x590D;&#x6570;,&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x6DF1;&#x5EA6;&#x4E3A;2
    mask[crow-30:crow+30, ccol-30:ccol+30] = 1  # &#x63A9;&#x819C;&#x4E2D;&#x5FC3;&#x7684;&#x4E00;&#x4E2A;&#x65B9;&#x5757;&#x7F6E;&#x4E3A;1
    # 5&#x3001;&#x4F4E;&#x901A;&#x6EE4;&#x6CE2;
    fshift = dft_shift*mask  # &#x4FDD;&#x7559;&#x4F4E;&#x9891;&#x90E8;&#x5206;&#x3001;
    # 6&#x3001;&#x9006;shift&#x53D8;&#x6362;
    f_ishift = np.fft.ifftshift(fshift)  # &#x4E4B;&#x524D;&#x8FDB;&#x884C;&#x4E86;shift,&#x8FD9;&#x91CC;&#x8981;&#x5148;&#x9006;shift,&#x518D;&#x5085;&#x91CC;&#x53F6;&#x53CD;&#x53D8;&#x6362;
    # 7&#x3001;&#x9006;&#x79BB;&#x6563;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;
    img_back = cv.idft(f_ishift)
    img_back = cv.magnitude(img_back[:, :, 0], img_back[:, :, 1])  # magnitude:&#x53D6;&#x6A21;
    # 8&#x3001;&#x663E;&#x793A;&#x53D8;&#x6362;&#x7ED3;&#x679C;(&#x4E2D;&#x95F4;&#x662F;&#x4F4E;&#x9891;,&#x8D8A;&#x5F80;&#x5916;&#x9891;&#x7387;&#x8D8A;&#x9AD8;)
    plt.subplot(121), plt.imshow(img_src, cmap="gray")  # &#x6E90;&#x56FE;&#x50CF;
    plt.subplot(122), plt.imshow(img_back, cmap="gray")  # &#x4F4E;&#x9891;&#x6EE4;&#x6CE2;&#x540E;
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程
&#x793A;&#x4F8B;&#x3001;&#x9AD8;&#x901A;&#x6EE4;&#x6CE2;&#x5668;&#x7684;&#x7B80;&#x5355;&#x5B9E;&#x73B0;(3)
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1 &#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img_src = cv.imread('lena.jpg', cv.IMREAD_GRAYSCALE)  # &#x4EE5;&#x7070;&#x5EA6;&#x683C;&#x5F0F;&#x8BFB;&#x53D6;&#x539F;&#x56FE;
    rows, cols = img_src.shape  # &#x56FE;&#x50CF;&#x5C3A;&#x5BF8;
    crow, ccol = int(rows/2), int(cols/2)  # &#x4E2D;&#x5FC3;&#x4F4D;&#x7F6E;
    img_float32 = np.float32(img_src)  # &#x8F6C;&#x6362;&#x6210;float32&#x7684;&#x683C;&#x5F0F;
    # 2&#x3001;&#x79BB;&#x6563;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;
    dft = cv.dft(img_float32, flags=cv.DFT_COMPLEX_OUTPUT)  # &#x6B63;&#x5411;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;
    # 3&#x3001;shift&#x53D8;&#x6362;
    dft_shift = np.fft.fftshift(dft)  # &#x5C06;&#x96F6;&#x9891;&#x70B9;&#x79FB;&#x5230;&#x9891;&#x8C31;&#x7684;&#x4E2D;&#x95F4;(shift&#x540E;,&#x4E2D;&#x95F4;&#x4E3A;&#x4F4E;&#x9891;&#x90E8;&#x5206;)
    # 4&#x3001;&#x521B;&#x5EFA;&#x63A9;&#x819C;,&#x4FDD;&#x7559;&#x4E2D;&#x5FC3;&#x7684;&#x63A9;&#x819C;
    mask = np.ones((rows, cols, 2), np.uint8)  # &#x56E0;&#x4E3A;&#x8F93;&#x51FA;&#x662F;&#x590D;&#x6570;,&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x6DF1;&#x5EA6;&#x4E3A;2
    mask[crow-30:crow+30, ccol-30:ccol+30] = 0  # &#x63A9;&#x819C;&#x4E2D;&#x5FC3;&#x7684;&#x4E00;&#x4E2A;&#x65B9;&#x5757;&#x7F6E;&#x4E3A;0
    # 5&#x3001;&#x4F4E;&#x901A;&#x6EE4;&#x6CE2;
    fshift = dft_shift*mask  # &#x4FDD;&#x7559;&#x4F4E;&#x9891;&#x90E8;&#x5206;&#x3001;
    # 6&#x3001;&#x9006;shift&#x53D8;&#x6362;
    f_ishift = np.fft.ifftshift(fshift)  # &#x4E4B;&#x524D;&#x8FDB;&#x884C;&#x4E86;shift,&#x8FD9;&#x91CC;&#x8981;&#x5148;&#x9006;shift,&#x518D;&#x5085;&#x91CC;&#x53F6;&#x53CD;&#x53D8;&#x6362;
    # 7&#x3001;&#x9006;&#x79BB;&#x6563;&#x5085;&#x91CC;&#x53F6;&#x53D8;&#x6362;
    img_back = cv.idft(f_ishift)
    img_back = cv.magnitude(img_back[:, :, 0], img_back[:, :, 1])  # magnitude:&#x53D6;&#x6A21;
    # 8&#x3001;&#x663E;&#x793A;&#x53D8;&#x6362;&#x7ED3;&#x679C;(&#x4E2D;&#x95F4;&#x662F;&#x4F4E;&#x9891;,&#x8D8A;&#x5F80;&#x5916;&#x9891;&#x7387;&#x8D8A;&#x9AD8;)
    plt.subplot(121), plt.imshow(img_src, cmap="gray")  # &#x6E90;&#x56FE;&#x50CF;
    plt.subplot(122), plt.imshow(img_back, cmap="gray")  # &#x4F4E;&#x9891;&#x6EE4;&#x6CE2;&#x540E;
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程

P1.26、角点检测之Harris

原理:

Harris角点检测的思想是通过图像的局部的小窗口观察图像,角点的特征是窗口沿任意方向移动都会导致图像灰度的明显变化,如下图所示:

38、OpenCV之C++教程

将上述思想转换为数学形式,即将局部窗口向各个方向移动(u,v)(u,v)并计算所有灰度差异的总和,表达式如下:

38、OpenCV之C++教程

其中I(x,y)是局部窗口的图像灰度,I(x+u,y+v)是平移后的图像灰度,w(x,y)是窗口函数,该可以是矩形窗口,也可以是对每一个像素赋予不同权重的高斯窗口,如下所示:

38、OpenCV之C++教程

角点检测中使E(u,v)的值最大。利用一阶泰勒展开有:

38、OpenCV之C++教程

其中I​x​​和I​y​​ 是沿x和y方向的导数,可用sobel算子计算。推导如下:

38、OpenCV之C++教程

M矩阵决定了E(u,v)的取值,下面我们利用M来求角点,M是I​x​​和I​y​​的二次项函数,可以表示成椭圆的形状,椭圆的长短半轴由M的特征值λ​1​​和λ​2​​决定,方向由特征矢量决定,如下图所示:

38、OpenCV之C++教程

椭圆函数特征值与图像中的角点、直线(边缘)和平面之间的关系如下图所示。

38、OpenCV之C++教程

共可分为三种情况:

  • 图像中的直线。一个特征值大,另一个特征值小,λ1>>λ2或 λ2>>λ1。椭圆函数值在某一方向上大,在其他方向上小。
  • 图像中的平面。两个特征值都小,且近似相等;椭圆函数数值在各个方向上都小。
  • 图像中的角点。两个特征值都大,且近似相等,椭圆函数在所有方向都增大

Harris给出的角点计算方法并不需要计算具体的特征值,而是计算一个 角点响应值R来判断角点。R的计算公式为:

38、OpenCV之C++教程

式中,detM为矩阵M的行列式;traceM为矩阵M的迹;α为常数,取值范围为0.04~0.06。事实上,特征是隐含在detM和traceM中,因为:

38、OpenCV之C++教程

那我们怎么判断角点呢?如下图所示:

38、OpenCV之C++教程
  • 当R为大数值的正数时是角点
  • 当R为大数值的负数时是边界
  • 当R为小数是认为是平坦区域

实现:

在OpenCV中实现Hariis检测使用的API是:

dst=cv.cornerHarris(src, blockSize, ksize, k)

参数:

  • img:数据类型为 float32 的输入图像。
  • blockSize:角点检测中要考虑的邻域大小。
  • ksize:sobel求导使用的核大小
  • k :角点检测方程中的自由参数,取值参数为 [0.04,0.06].

示例:

&#x793A;&#x4F8B;25&#x3001;Harries
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;&#xFF0C;&#x5E76;&#x8F6C;&#x6362;&#x6210;&#x7070;&#x5EA6;&#x56FE;&#x50CF;
    img = cv.imread('chessboard.jpg')
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    # 2&#x3001;&#x89D2;&#x70B9;&#x68C0;&#x6D4B;
    # 2.1 &#x8F93;&#x5165;&#x56FE;&#x50CF;&#x5FC5;&#x987B;&#x662F; float32
    gray = np.float32(gray)
    # 2.2 &#x6700;&#x540E;&#x4E00;&#x4E2A;&#x53C2;&#x6570;&#x5728; 0.04 &#x5230; 0.05 &#x4E4B;&#x95F4;
    dst = cv.cornerHarris(gray, 2, 3, 0.04)
    # 3&#x3001;&#x8BBE;&#x7F6E;&#x9608;&#x503C;&#xFF0C;&#x5C06;&#x89D2;&#x70B9;&#x7ED8;&#x5236;&#x51FA;&#x6765;&#xFF0C;&#x9608;&#x503C;&#x6839;&#x636E;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x9009;&#x62E9;
    img[dst > 0.001 * dst.max()] = [0, 0, 255]
    # 4&#x3001;&#x56FE;&#x50CF;&#x663E;&#x793A;
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1]), plt.title('Harris&#x89D2;&#x70B9;&#x68C0;&#x6D4B;')
    plt.xticks([]), plt.yticks([])
    plt.show()
    # x&#x3001;&#x4F7F;&#x7528;matplot&#x8FDB;&#x884C;&#x56FE;&#x50CF;&#x663E;&#x793A;
    #plt.subplot(1, 2, 1), plt.imshow(xx, cmap=plt.cm.gray), plt.title("&#x7070;&#x5EA6;&#x56FE;&#x7684;&#x4E2D;&#x503C;")
    #plt.subplot(1, 2, 2), plt.imshow(xx[:, :, ::-1]), plt.title("&#x970D;&#x592B;&#x5706;&#x68C0;&#x6D4B;")
    #plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程

P1.27、角点检测之Shi-Tomas

原理:

Shi-Tomasi算法是对Harris角点检测算法的改进,一般会比Harris算法得到更好的角点。Harris 算法的角点响应函数是将矩阵 M 的行列式值与 M 的迹相减,利用差值判断是否为角点。后来Shi 和Tomasi 提出改进的方法是,若矩阵M的两个特征值中较小的一个大于阈值,则认为他是角点,即:

R=min(λ​1​​,λ​2​​)

如下图所示:

38、OpenCV之C++教程

从这幅图中,可以看出来只有当 λ1 和 λ 2 都大于最小值时,才被认为是角点。

实现:

在OpenCV中实现Shi-Tomasi角点检测使用API:

corners = cv2.goodFeaturesToTrack ( image, maxcorners, qualityLevel, minDistance )

参数:

  • Image: 输入灰度图像
  • maxCorners : 获取角点数的数目。
  • qualityLevel:该参数指出最低可接受的角点质量水平,在0-1之间。
  • minDistance:角点之间最小的欧式距离,避免得到相邻特征点。

返回:

  • Corners: 搜索到的角点,在这里所有低于质量水平的角点被排除掉,然后把合格的角点按质量排序,然后将质量较好的角点附近(小于最小欧式距离)的角点删掉,最后找到maxCorners个角点返回。

示例:

&#x793A;&#x4F8B;26&#x3001;Shi-Tomas&#x89D2;&#x70B9;&#x68C0;&#x6D4B;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1 &#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img = cv.imread('tv.jpg')
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    # 2 &#x89D2;&#x70B9;&#x68C0;&#x6D4B;
    corners = cv.goodFeaturesToTrack(gray, 1000, 0.01, 10)
    # 3 &#x7ED8;&#x5236;&#x89D2;&#x70B9;
    for i in corners:
        x, y = i.ravel()
        cv.circle(img, (x, y), 2, (0, 0, 255), -1)
    # 4 &#x56FE;&#x50CF;&#x5C55;&#x793A;
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1]), plt.title('shi-tomasi&#x89D2;&#x70B9;&#x68C0;&#x6D4B;')
    plt.xticks([]), plt.yticks([])
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程

P1.28、角点检测之SIFT/SURF

前面两节我们介绍了Harris和Shi-Tomasi角点检测算法,这两种算法具有旋转不变性,但不具有尺度不变性,以下图为例,在左侧小图中可以检测到角点,但是图像被放大后,在使用同样的窗口,就检测不到角点了。

38、OpenCV之C++教程

所以,下面我们来介绍一种计算机视觉的算法,尺度不变特征转换即SIFT (Scale-invariant feature transform)。它用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由 David Lowe在1999年所发表,2004年完善总结。应用范围包含物体辨识、机器人地图感知与导航、影像缝合、3D模型建立、手势辨识、影像追踪和动作比对等领域。

SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如 角点、边缘点、暗区的亮点及亮区的暗点等。

Lowe将SIFT算法分解为如下 四步

  1. 尺度空间极值检测:搜索所有尺度上的图像位置。通过高斯差分函数来识别潜在的对于尺度和旋转不变的关键点。
  2. 关键点定位:在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于它们的稳定程度。
  3. 关键点方向确定:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,从而保证了对于这些变换的不变性。
  4. 关键点描述:在每个关键点周围的邻域内,在选定的尺度上测量图像局部的梯度。这些梯度作为关键点的描述符,它允许比较大的局部形状的变形或光照变化。

我们就沿着Lowe的步骤,对SIFT算法的实现过程进行介绍:

在不同的尺度空间是不能使用相同的窗口检测极值点,对小的关键点使用小的窗口,对大的关键点使用大的窗口,为了达到上述目的,我们使用尺度空间滤波器。

高斯核是唯一可以产生多尺度空间的核函数。-《Scale-space theory: A basic tool for analysing structures at different scales》。

一个图像的尺度空间L(x,y,σ),定义为原始图像I(x,y)与一个可变尺度的2维高斯函数G(x,y,σ)卷积运算 ,即:

L(x,y,σ)=G(x,y,σ)∗I(x,y)

其中:

38、OpenCV之C++教程

σ是尺度空间因子,它决定了图像的模糊的程度。在大尺度下(\sigmaσ值大)表现的是图像的概貌信息,在小尺度下(\sigmaσ值小)表现的是图像的细节信息。

在计算高斯函数的离散近似时,在大概3σ距离之外的像素都可以看作不起作用,这些像素的计算也就可以忽略。所以,在实际应用中,只计算 (6σ+1)*(6σ+1)的高斯卷积核就可以保证相关像素影响。

下面我们构建图像的高斯金字塔,它采用高斯函数对图像进行模糊以及降采样处理得到的,高斯金字塔构建过程中,首先将图像扩大一倍,在扩大的图像的基础之上构建高斯金字塔,然后对该尺寸下图像进行高斯模糊,几幅模糊之后的图像集合构成了一个Octave,然后对该Octave下选择一幅图像进行下采样,长和宽分别缩短一倍,图像面积变为原来四分之一。这幅图像就是下一个Octave的初始图像,在初始图像的基础上完成属于这个Octave的高斯模糊处理,以此类推完成整个算法所需要的所有八度构建,这样这个高斯金字塔就构建出来了,整个流程如下图所示:

38、OpenCV之C++教程

利用LoG(高斯拉普拉斯方法),即图像的二阶导数,可以在不同的尺度下检测图像的关键点信息,从而确定图像的特征点。但LoG的计算量大,效率低。所以我们通过两个相邻高斯尺度空间的图像的相减,得到DoG(高斯差分)来近似LoG。

为了计算DoG我们构建高斯差分金字塔,该金字塔是在上述的高斯金字塔的基础上构建而成的,建立过程是:在高斯金字塔中每个Octave中相邻两层相减就构成了高斯差分金字塔。如下图所示:

38、OpenCV之C++教程

高斯差分金字塔的第1组第1层是由高斯金字塔的第1组第2层减第1组第1层得到的。以此类推,逐组逐层生成每一个差分图像,所有差分图像构成差分金字塔。概括为DOG金字塔的第o组第l层图像是有高斯金字塔的第o组第l+1层减第o组第l层得到的。后续Sift特征点的提取都是在DOG金字塔上进行的

在 DoG 搞定之后,就可以在不同的尺度空间中搜索局部最大值了。对于图像中的一个像素点而言,它需要与自己周围的 8 邻域,以及尺度空间中上下两层中的相邻的 18(2×9)个点相比。如果是局部最大值,它就可能是一个关键点。基本上来说关键点是图像在相应尺度空间中的最好代表。如下图所示:

38、OpenCV之C++教程

搜索过程从每组的第二层开始,以第二层为当前层,对第二层的DoG图像中的每个点取一个3×3的立方体,立方体上下层为第一层与第三层。这样,搜索得到的极值点既有位置坐标(DoG的图像坐标),又有空间尺度坐标(层坐标)。当第二层搜索完成后,再以第三层作为当前层,其过程与第二层的搜索类似。当S=3时,每组里面要搜索3层,所以在DOG中就有S+2层,在初使构建的金字塔中每组有S+3层。

由于DoG对噪声和边缘比较敏感,因此在上面高斯差分金字塔中检测到的局部极值点需经过进一步的检验才能精确定位为特征点。

使用尺度空间的泰勒级数展开来获得极值的准确位置, 如果 极值点的 灰度值小于阈值(一般为0.03或0.04)就会被忽略掉。 在 OpenCV 中这种阈值被称为 contrastThreshold。

DoG 算法对边界非常敏感, 所以我们必须要把边界去除。 Harris 算法除了可以用于角点检测之外还可以用于检测边界。从 Harris 角点检测的算法中,当一个特征值远远大于另外一个特征值时检测到的是边界。那在DoG算法中欠佳的关键点在平行边缘的方向有较大的主曲率,而在垂直于边缘的方向有较小的曲率,两者的比值如果高于某个阈值(在OpenCV中叫做边界阈值),就认为该关键点为边界,将被忽略,一般将该阈值设置为10。

将低对比度和边界的关键点去除,得到的就是我们感兴趣的关键点。

经过上述两个步骤,图像的关键点就完全找到了,这些关键点具有尺度不变性。为了实现旋转不变性,还需要为每个关键点分配一个方向角度,也就是根据检测到的关键点所在高斯尺度图像的邻域结构中求得一个方向基准。

对于任一关键点,我们采集其所在高斯金字塔图像以r为半径的区域内所有像素的梯度特征(幅值和幅角),半径r为:

r = 3×1.5σ

其中σ是关键点所在octave的图像的尺度,可以得到对应的尺度图像。

梯度的幅值和方向的计算公式为:

38、OpenCV之C++教程

邻域像素梯度的计算结果如下图所示:

38、OpenCV之C++教程

完成关键点梯度计算后,使用直方图统计关键点邻域内像素的梯度幅值和方向。具体做法是,将360°分为36柱,每10°为一柱,然后在以r为半径的区域内,将梯度方向在某一个柱内的像素找出来,然后将他们的幅值相加在一起作为柱的高度。因为在r为半径的区域内像素的梯度幅值对中心像素的贡献是不同的,因此还需要对幅值进行加权处理,采用高斯加权,方差为1.5σ。如下图所示,为简化图中只画了8个方向的直方图。

38、OpenCV之C++教程

每个特征点必须分配一个主方向,还需要一个或多个辅方向,增加辅方向的目的是为了增强图像匹配的鲁棒性。辅方向的定义是,当一个柱体的高度大于主方向柱体高度的80%时,则该柱体所代表的的方向就是给特征点的辅方向。

直方图的峰值,即最高的柱代表的方向是特征点邻域范围内图像梯度的主方向,但该柱体代表的角度是一个范围,所以我们还要对离散的直方图进行插值拟合,以得到更精确的方向角度值。利用抛物线对离散的直方图进行拟合,如下图所示:

38、OpenCV之C++教程

获得图像关键点主方向后,每个关键点有三个信息(x,y,σ,θ):位置、尺度、方向。由此我们可以确定一个SIFT特征区域。通常使用一个带箭头的圆或直接使用箭头表示SIFT区域的三个值:中心表示特征点位置,半径表示关键点尺度,箭头表示方向。如下图所示:

38、OpenCV之C++教程

通过以上步骤,每个关键点就被分配了位置,尺度和方向信息。接下来我们为每个关键点建立一个描述符,该描述符既具有可区分性,又具有对某些变量的不变性,如光照,视角等。而且描述符不仅仅包含关键点,也包括关键点周围对其有贡献的的像素点。主要思路就是通过将关键点周围图像区域分块,计算块内的梯度直方图,生成具有特征向量,对图像信息进行抽象。

描述符与特征点所在的尺度有关,所以我们在关键点所在的高斯尺度图像上生成对应的描述符。以特征点为中心,将其附近邻域划分为d∗d个子区域(一般取d=4),每个子区域都是一个正方形,边长为3σ,考虑到实际计算时,需进行三次线性插值,所以特征点邻域的为3σ(d+1)∗3σ(d+1)的范围,如下图所示:

38、OpenCV之C++教程

为了保证特征点的旋转不变性,以特征点为中心,将坐标轴旋转为关键点的主方向,如下图所示:

38、OpenCV之C++教程

计算子区域内的像素的梯度,并按照σ=0.5d进行高斯加权,然后插值计算得到每个种子点的八个方向的梯度,插值方法如下图所示:

38、OpenCV之C++教程

每个种子点的梯度都是由覆盖其的4个子区域插值而得的。如图中的红色点,落在第0行和第1行之间,对这两行都有贡献。对第0行第3列种子点的贡献因子为dr,对第1行第3列的贡献因子为1-dr,同理,对邻近两列的贡献因子为dc和1-dc,对邻近两个方向的贡献因子为do和1-do。则最终累加在每个方向上的梯度大小为:

38、OpenCV之C++教程

其中k,m,n为0或为1。 如上统计448=1284∗4∗8=128个梯度信息即为该关键点的特征向量,按照特征点的对每个关键点的特征向量进行排序,就得到了SIFT特征描述向量。

SIFT在图像的不变特征提取方面拥有无与伦比的优势,但并不完美,仍然存在实时性不高,有时特征点较少,对边缘光滑的目标无法准确提取特征点等缺陷,自SIFT算法问世以来,人们就一直对其进行优化和改进,其中最著名的就是SURF算法。

使用 SIFT 算法进行关键点检测和描述的执行速度比较慢, 需要速度更快的算法。 2006 年 Bay提出了 SURF 算法,是SIFT算法的增强版,它的计算量小,运算速度快,提取的特征与SIFT几乎相同,将其与SIFT算法对比如下

38、OpenCV之C++教程

在OpenCV中利用SIFT检测关键点的流程如下所示:

第一步、实例化sift :

sift = cv.xfeatures2d.SIFT_create()

第二步、利用sift.detectAndCompute()检测关键点并计算

kp,des = sift.detectAndCompute(gray,None)

参数:

  • gray: 进行关键点检测的图像,注意是灰度图像

返回:

  • kp: 关键点信息,包括位置,尺度,方向信息
  • des: 关键点描述符,每个关键点对应128个梯度信息的特征向量

第三步、将关键点检测结果绘制在图像上

cv.drawKeypoints(image, keypoints, outputimage, color, flags)

参数:

  • image: 原始图像
  • keypoints:关键点信息,将其绘制在图像上
  • outputimage:输出图片,可以是原始图像
  • color:颜色设置,通过修改(b,g,r)的值,更改画笔的颜色,b=蓝色,g=绿色,r=红色。
  • flags:绘图功能的标识设置
  • cv2.DRAW_MATCHES_FLAGS_DEFAULT:创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征点,对每一个关键点只绘制中间点
  • cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG:不创建输出图像矩阵,而是在输出图像上绘制匹配对
  • cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS:对每一个特征点绘制带大小和方向的关键点图形
  • cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制

SURF算法的应用与上述流程是一致,这里就不在赘述。

示例:利用SIFT算法在中央电视台的图片上检测关键点,并将其绘制出来:

&#x793A;&#x4F8B;&#x3001;SIFT/SURF&#x7B97;&#x6CD5;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1 &#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img = cv.imread('tv.jpg')
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    # 2 sift&#x5173;&#x952E;&#x70B9;&#x68C0;&#x6D4B;
    # 2.1 &#x5B9E;&#x4F8B;&#x5316;sift&#x5BF9;&#x8C61;
    sift = cv.xfeatures2d.SIFT_create()

    # 2.2 &#x5173;&#x952E;&#x70B9;&#x68C0;&#x6D4B;&#xFF1A;kp&#x5173;&#x952E;&#x70B9;&#x4FE1;&#x606F;&#x5305;&#x62EC;&#x65B9;&#x5411;&#xFF0C;&#x5C3A;&#x5EA6;&#xFF0C;&#x4F4D;&#x7F6E;&#x4FE1;&#x606F;&#xFF0C;des&#x662F;&#x5173;&#x952E;&#x70B9;&#x7684;&#x63CF;&#x8FF0;&#x7B26;
    kp, des = sift.detectAndCompute(gray, None)
    # 2.3 &#x5728;&#x56FE;&#x50CF;&#x4E0A;&#x7ED8;&#x5236;&#x5173;&#x952E;&#x70B9;&#x7684;&#x68C0;&#x6D4B;&#x7ED3;&#x679C;
    cv.drawKeypoints(img, kp, img, flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    # 3 &#x56FE;&#x50CF;&#x663E;&#x793A;
    plt.figure(figsize=(8, 6), dpi=100)
    plt.imshow(img[:, :, ::-1]), plt.title('sift&#x68C0;&#x6D4B;')
    plt.xticks([]), plt.yticks([])
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程

P1.29、角点检测之FAST

我们前面已经介绍过几个特征检测器,它们的效果都很好,特别是SIFT和SURF算法,但是从实时处理的角度来看,效率还是太低了。为了解决这个问题,Edward Rosten和Tom Drummond在2006年提出了FAST算法,并在2010年对其进行了修正。

(全称Features from accelerated segment test)是一种用于角点检测的算法,该算法的原理是取图像中检测点,以该点为圆心的周围邻域内像素点判断检测点是否为角点,通俗的讲就是若一个像素周围有一定数量的像素与该点像素值不同,则认为其为角点

  1. 在图像中选取一个像素点 p,来判断它是不是关键点。Ip等于像素点 p的灰度值。

  2. 以r为半径画圆,覆盖p点周围的M个像素,通常情况下,设置 r=3,则 M=16,如下图所示:

38、OpenCV之C++教程
  1. 设置一个阈值t,如果在这 16 个像素点中存在 n 个连续像素点的灰度值都高于Ip + t,或者低于Ip – t,那么像素点 p 就被认为是一个角点。如上图中的虚线所示,n 一般取值为 12。

  2. 由于在检测特征点时是需要对图像中所有的像素点进行检测,然而图像中的绝大多数点都不是特征点,如果对每个像素点都进行上述的检测过程,那显然会浪费许多时间,因此采用一种进行**非特征点判别的方法:首先对候选点的周围每个 90 度的点:1,9,5,13 进行测试(先测试 1 和 19, 如果它们符合阈值要求再测试 5 和 13)。如果 p 是角点,那么这四个点中至少有 3 个要符合阈值要求,否则直接剔除。对保留下来的点再继续进行测试(是否有 12 的点符合阈值要求)。

虽然这个检测器的效率很高,但它有以下几条缺点:

  • 获得的候选点比较多
  • 特征点的选取不是最优的,因为它的效果取决与要解决的问题和角点的分布情况。
  • 进行非特征点判别时大量的点被丢弃
  • 检测到的很多特征点都是相邻的

前 3 个问题可以通过机器学习的方法解决,最后一个问题可以使用非最大值抑制的方法解决。

  1. 选择一组训练图片(最好是跟最后应用相关的图片)

  2. 使用 FAST 算法找出每幅图像的特征点,对图像中的每一个特征点,将其周围的 16 个像素存储构成一个向量P。

38、OpenCV之C++教程
  1. 每一个特征点的 16 像素点都属于下列三类中的一种

38、OpenCV之C++教程
  1. 根据这些像素点的分类,特征向量 P 也被分为 3 个子集:Pd ,Ps ,Pb,

  2. 定义一个新的布尔变量Kp,如果 p 是角点就设置为 Ture,如果不是就设置为 False。

  3. 利用特征值向量p,目标值是Kp,训练ID3 树(决策树分类器)。

  4. 将构建好的决策树运用于其他图像的快速的检测。

在筛选出来的候选角点中有很多是紧挨在一起的,需要通过非极大值抑制来消除这种影响。

为所有的候选角点都确定一个打分函数V,V的值可这样计算:先分别计算Ip与圆上16个点的像素值差值,取绝对值,再将这16个绝对值相加,就得到了V的值

38、OpenCV之C++教程

最后比较毗邻候选角点的 V 值,把V值较小的候选角点pass掉。

FAST算法的思想与我们对角点的直观认识非常接近,化繁为简。FAST算法比其它角点的检测算法快,但是在噪声较高时不够稳定,这需要设置合适的阈值。

API:fast = =cv.FastFeatureDetector_create( threshold, nonmaxSuppression)

参数:

  • threshold:阈值t,有默认值10
  • nonmaxSuppression:是否进行非极大值抑制,默认值True

返回:

  • Fast:创建的FastFeatureDetector对象

API:kp = fast.detect(grayImg, None)

参数:- gray: 进行关键点检测的图像,注意是灰度图像

返回:- kp: 关键点信息,包括位置,尺度,方向信息

API:cv.drawKeypoints(image, keypoints, outputimage, color, flags)

&#x793A;&#x4F8B;&#x3001;FAST&#x89D2;&#x70B9;&#x68C0;&#x6D4B;
OpenCV&#x4F7F;&#x7528;&#x7684;&#x662F;&#x4F20;&#x7EDF;&#x65B9;&#x6CD5;,&#x5E76;&#x6CA1;&#x6709;&#x4F7F;&#x7528;&#x673A;&#x5668;&#x5B66;&#x4E60;&#x7684;&#x65B9;&#x6CD5;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1 &#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img = cv.imread('tv.jpg')
    # 2 Fast&#x89D2;&#x70B9;&#x68C0;&#x6D4B;
    # 2.1 &#x521B;&#x5EFA;&#x4E00;&#x4E2A;Fast&#x5BF9;&#x8C61;&#xFF0C;&#x4F20;&#x5165;&#x9608;&#x503C;&#xFF0C;&#x6CE8;&#x610F;&#xFF1A;&#x53EF;&#x4EE5;&#x5904;&#x7406;&#x5F69;&#x8272;&#x7A7A;&#x95F4;&#x56FE;&#x50CF;
    fast = cv.FastFeatureDetector_create(threshold=30)

    # 2.2 &#x68C0;&#x6D4B;&#x56FE;&#x50CF;&#x4E0A;&#x7684;&#x5173;&#x952E;&#x70B9;
    kp = fast.detect(img, None)
    # 2.3 &#x5728;&#x56FE;&#x50CF;&#x4E0A;&#x7ED8;&#x5236;&#x5173;&#x952E;&#x70B9;
    img2 = cv.drawKeypoints(img, kp, None, color=(0, 0, 255))

    # 2.4 &#x8F93;&#x51FA;&#x9ED8;&#x8BA4;&#x53C2;&#x6570;
    print("Threshold: {}".format(fast.getThreshold()))
    print("nonmaxSuppression:{}".format(fast.getNonmaxSuppression()))
    print("neighborhood: {}".format(fast.getType()))
    print("Total Keypoints with nonmaxSuppression: {}".format(len(kp)))

    # 2.5 &#x5173;&#x95ED;&#x975E;&#x6781;&#x5927;&#x503C;&#x6291;&#x5236;
    fast.setNonmaxSuppression(0)
    kp = fast.detect(img, None)

    print("Total Keypoints without nonmaxSuppression: {}".format(len(kp)))
    # 2.6 &#x7ED8;&#x5236;&#x4E3A;&#x8FDB;&#x884C;&#x975E;&#x6781;&#x5927;&#x503C;&#x6291;&#x5236;&#x7684;&#x7ED3;&#x679C;
    img3 = cv.drawKeypoints(img, kp, None, color=(0, 0, 255))

    # 3 &#x7ED8;&#x5236;&#x56FE;&#x50CF;
    fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
    axes[0].imshow(img2[:, :, ::-1])
    axes[0].set_title("&#x52A0;&#x5165;&#x975E;&#x6781;&#x5927;&#x503C;&#x6291;&#x5236;")
    axes[1].imshow(img3[:, :, ::-1])
    axes[1].set_title("&#x672A;&#x52A0;&#x5165;&#x975E;&#x6781;&#x5927;&#x503C;&#x6291;&#x5236;")
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程

P1.30、角点检测之ORB

SIFT和SURF算法是受专利保护的,在使用他们时我们是要付费的,但是ORB(Oriented Fast and Rotated Brief)不需要,它可以用来对图像中的关键点快速创建特征向量,并用这些特征向量来识别图像中的对象。

ORB算法结合了Fast和Brief算法,提出了构造金字塔,为Fast特征点添加了方向,从而使得关键点具有了尺度不变性和旋转不变性。具体流程描述如下:

  • 构造尺度金字塔,金字塔共有n层,与SIFT不同的是,每一层仅有一幅图像。第s层的尺度为:

38、OpenCV之C++教程

σ0是初始尺度,默认为1.2,原图在第0层。

38、OpenCV之C++教程

第s层图像的大小:

38、OpenCV之C++教程
  • 在不同的尺度上利用Fast算法检测特征点,采用Harris角点响应函数,根据角点的响应值排序,选取前N个特征点,作为本尺度的特征点。

  • 计算特征点的主方向,计算以特征点为圆心半径为r的圆形邻域内的灰度质心位置,将从特征点位置到质心位置的方向做特征点的主方向。

38、OpenCV之C++教程
  • 为了解决旋转不变性,将特征点的邻域旋转到主方向上利用Brief算法构建特征描述符,至此就得到了ORB的特征描述向量。

BRIEF是一种特征描述子提取算法,并非特征点的提取算法,一种生成二值化描述子的算法,不提取代价低,匹配只需要使用简单的汉明距离(Hamming Distance)利用比特之间的异或操作就可以完成。因此,时间代价低,空间代价低,效果还挺好是最大的优点。

算法的步骤介绍如下

  1. 图像滤波:原始图像中存在噪声时,会对结果产生影响,所以需要对图像进行滤波,去除部分噪声。

  2. 选取点对:以特征点为中心,取S*S的邻域窗口,在窗口内随机选取N组点对,一般N=128,256,512,默认是256,关于如何选取随机点对,提供了五种形式,结果如下图所示:

  3. x,y方向平均分布采样

  4. x,y均服从Gauss(0,S^2/25)各向同性采样

  5. x服从Gauss(0,S^2/25),y服从Gauss(0,S^2/100)采样

  6. x,y从网格中随机获取

  7. x一直在(0,0),y从网格中随机选取

38、OpenCV之C++教程

图中一条线段的两个端点就是一组点对,其中第二种方法的结果比较好。

  1. 构建描述符:假设x,y是某个点对的两个端点,p(x),p(y)是两点对应的像素值,则有:

38、OpenCV之C++教程

对每一个点对都进行上述的二进制赋值,形成BRIEF的关键点的描述特征向量,该向量一般为 128-512 位的字符串,其中仅包含 1 和 0,如下图所示:

38、OpenCV之C++教程

1、实例化ORB对象
orb = cv.xfeatures2d.orb_create(nfeatures)
2、利用orb.detectAndCompute()检测关键点并计算
参数:- nfeatures: 特征点的最大数量
kp,des = orb.detectAndCompute(gray,None)
参数:
– gray: 进行关键点检测的图像,注意是灰度图像
返回:
– kp: 关键点信息,包括位置,尺度,方向信息
– des: 关键点描述符,每个关键点BRIEF特征向量,二进制字符串,
3、将关键点检测结果绘制在图像上
cv.drawKeypoints(image, keypoints, outputimage, color, flags)

&#x793A;&#x4F8B;&#x3001;ORB&#x89D2;&#x70B9;&#x68C0;&#x6D4B;
OpenCV&#x4F7F;&#x7528;&#x7684;&#x662F;&#x4F20;&#x7EDF;&#x65B9;&#x6CD5;,&#x5E76;&#x6CA1;&#x6709;&#x4F7F;&#x7528;&#x673A;&#x5668;&#x5B66;&#x4E60;&#x7684;&#x65B9;&#x6CD5;
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4E3B;&#x51FD;&#x6570;
if __name__ == '__main__':
    # 1 &#x56FE;&#x50CF;&#x8BFB;&#x53D6;
    img = cv.imread('tv.jpg')
    # 2 ORB&#x89D2;&#x70B9;&#x68C0;&#x6D4B;
    # 2.1 &#x5B9E;&#x4F8B;&#x5316;ORB&#x5BF9;&#x8C61;
    orb = cv.ORB_create(nfeatures=5000)
    # 2.2 &#x68C0;&#x6D4B;&#x5173;&#x952E;&#x70B9;,&#x5E76;&#x8BA1;&#x7B97;&#x7279;&#x5F81;&#x63CF;&#x8FF0;&#x7B26;
    kp, des = orb.detectAndCompute(img, None)
    print(des.shape)
    # 3 &#x5C06;&#x5173;&#x952E;&#x70B9;&#x7ED8;&#x5236;&#x5728;&#x56FE;&#x50CF;&#x4E0A;
    img2 = cv.drawKeypoints(img, kp, None, flags=0)
    # 4. &#x7ED8;&#x5236;&#x56FE;&#x50CF;
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img2[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
&#x8BBF;&#x95EE; https://www.jetbrains.com/help/pycharm/ &#x83B7;&#x53D6; PyCharm &#x5E2E;&#x52A9;

38、OpenCV之C++教程

P1.31、视频操作

&#x793A;&#x4F8B;1:&#x89C6;&#x9891;&#x7684;&#x8BFB;&#x53D6;&#x4E0E;&#x663E;&#x793A;
import cv2 as cv
&#x7A0B;&#x5E8F;&#x7684;&#x8FD0;&#x884C;&#x8D77;&#x70B9;&#x3001;main()
if __name__ == '__main__':
    # 1&#x3001;&#x6253;&#x5F00;&#x89C6;&#x9891;&#x6587;&#x4EF6;
    cap = cv.VideoCapture("nascar.mp4")  # &#x8BFB;&#x53D6;&#x89C6;&#x9891;&#x6587;&#x4EF6;
    if cap.isOpened():  # &#x5224;&#x65AD;&#x89C6;&#x9891;&#x5BF9;&#x8C61;&#x662F;&#x5426;&#x6253;&#x5F00;&#x6210;&#x529F;
        flag = True
    else:
        flag = False
    # 2&#x3001;&#x5FAA;&#x73AF;&#x663E;&#x793A;&#x6BCF;&#x5E27;
    while flag:
        ret, frame = cap.read()  # &#x5FAA;&#x73AF;&#x8BFB;&#x53D6;&#x6BCF;&#x5E27;
        if ret:
            cv.imshow("result_win", frame)
            if (cv.waitKey(20) & 0xFF) == ord("q"):  # &#x68C0;&#x6D4B;&#x5230;q&#x6309;&#x952E;&#x5219;&#x9000;&#x51FA;
                break
        else:
            break
    cap.release()
    cv.destroyWindow("result_win")
&#x793A;&#x4F8B;2:&#x6444;&#x50CF;&#x5934;&#x7684;&#x8BFB;&#x53D6;&#x4E0E;&#x663E;&#x793A;
import cv2 as cv
&#x7A0B;&#x5E8F;&#x7684;&#x8FD0;&#x884C;&#x8D77;&#x70B9;&#x3001;main()
if __name__ == '__main__':
    # 1&#x3001;&#x6253;&#x5F00;&#x6444;&#x50CF;&#x5934;
    cap = cv.VideoCapture(0)
    if cap.isOpened():
        flag = True
    else:
        flag = False
    # 2&#x3001;&#x5FAA;&#x73AF;&#x663E;&#x793A;&#x6BCF;&#x5E27;
    while flag:
        ret, frame = cap.read()  # &#x5FAA;&#x73AF;&#x8BFB;&#x53D6;&#x6BCF;&#x5E27;
        if ret:
            frame = cv.flip(frame, 1)  # &#x56FE;&#x50CF;&#x5DE6;&#x53F3;&#x955C;&#x50CF;
            cv.imshow("result_win", frame)
            if (cv.waitKey(10) & 0xFF) == ord("q"):  # &#x68C0;&#x6D4B;&#x5230;q&#x6309;&#x952E;&#x5219;&#x9000;&#x51FA;
                break
        else:
            break
    cap.release()
    cv.destroyWindow("result_win")

P1.32、基于OpenCV的人脸识别

前言:OpenCV的人脸识别算法(以3.4.1.15为例),其能实现基础的人脸识别,但你使用后会发现,其识别的准确率并不是很好(做毕设没问题),使用的算法也是很老的算法,如果你想要更好更高的准确率,(1)你可以研究更高的OpenCV版本带的算法(高版本商用可能会收费),(2)你可以使用其他的开源算法。我建议使用第二种方式,毕竟深度学习现在很火。

< 示例一:识别图像中所有的人脸>

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x4EBA;&#x8138;&#x68C0;&#x6D4B;&#x51FD;&#x6570;
def face_detect_demo():
    img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # &#x56FE;&#x50CF;&#x8F6C;&#x4E3A;&#x7070;&#x5EA6;&#x56FE;
    face_detect = cv.CascadeClassifier("haarcascade_frontalface_alt2.xml")  # &#x52A0;&#x8F7D;OpenCV&#x7684;&#x5206;&#x7C7B;&#x5668;
    face = face_detect.detectMultiScale(img_gray)
    for x, y, w, h in face:
        cv.rectangle(img, (x, y), (x+w, y+w), color=(0, 0, 255), thickness=2)
    cv.imshow("result", img)
    cv.waitKey(0)

&#x6309;&#x95F4;&#x8DDD;&#x4E2D;&#x7684;&#x7EFF;&#x8272;&#x6309;&#x94AE;&#x4EE5;&#x8FD0;&#x884C;&#x811A;&#x672C;&#x3002;
if __name__ == '__main__':
    # 1&#x3001;&#x8BFB;&#x53D6;&#x56FE;&#x50CF;
    img_src = cv.imread("suoerwei.png", cv.IMREAD_UNCHANGED)
    img_gray = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY)
    # 2&#x3001;&#x52A0;&#x8F7D;OpenCV&#x5206;&#x7C7B;&#x5668;
    face_detect = cv.CascadeClassifier("haarcascade_frontalface_alt2.xml")  # &#x52A0;&#x8F7D;OpenCV&#x81EA;&#x5E26;&#x7684;&#x5206;&#x7C7B;&#x5668;
    # 3&#x3001;&#x4F7F;&#x7528;&#x5206;&#x7C7B;&#x5668;&#x5BF9;&#x56FE;&#x50CF;&#x8FDB;&#x884C;&#x68C0;&#x6D4B;
    face = face_detect.detectMultiScale(img_gray)
    # 4&#x3001;&#x628A;&#x68C0;&#x6D4B;&#x51FA;&#x7684;&#x7ED3;&#x679C;&#x7ED8;&#x5236;&#x5728;&#x539F;&#x56FE;&#x4E0A;
    for x, y, w, h in face:
        cv.rectangle(img_src, (x, y), (x+w, y+w), color=(0, 0, 255), thickness=2)
    # 5&#x3001;&#x663E;&#x793A;&#x68C0;&#x6D4B;&#x7ED3;&#x679C;
    cv.imshow("result", img_src)
    cv.waitKey(0)
&#x6CE8;&#x610F;&#xFF1A;OpenCV&#x7684;&#x5206;&#x7C7B;&#x5668;&#x4E0D;&#x6B62;&#x4E00;&#x4E2A;,&#x53EF;&#x81EA;&#x884C;&#x5C1D;&#x8BD5;&#x5176;&#x5B83;&#x7684;

38、OpenCV之C++教程

< 示例二:识别摄像头和视频中的所有人脸>

&#x793A;&#x4F8B;:&#x8BC6;&#x522B;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x4EBA;&#x8138;
import cv2 as cv
&#x7A0B;&#x5E8F;&#x7684;&#x8FD0;&#x884C;&#x8D77;&#x70B9;&#x3001;main()
if __name__ == '__main__':
    # 0&#x3001;&#x52A0;&#x8F7D;&#x4EBA;&#x8138;&#x8BC6;&#x522B;&#x5668;
    faces_detect = cv.CascadeClassifier("haarcascade_frontalface_alt.xml")
    # 1&#x3001;&#x6253;&#x5F00;&#x6444;&#x50CF;&#x5934;
    cap = cv.VideoCapture(0)
    if cap.isOpened():
        flag = True
    else:
        flag = False
    # 2&#x3001;&#x5FAA;&#x73AF;&#x663E;&#x793A;&#x6BCF;&#x5E27;
    while flag:
        ret, frame = cap.read()  # &#x5FAA;&#x73AF;&#x8BFB;&#x53D6;&#x6BCF;&#x5E27;
        if ret:
            frame = cv.flip(frame, 1)  # &#x56FE;&#x50CF;&#x5DE6;&#x53F3;&#x955C;&#x50CF;
            # &#x68C0;&#x6D4B;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x4EBA;&#x8138;
            faces = faces_detect.detectMultiScale(frame)  # &#x68C0;&#x6D4B;&#x4EBA;&#x8138;
            for x, y, w, h in faces:
                cv.rectangle(frame, (x, y), (x + w, y + w), color=(0, 0, 255), thickness=1)
            # &#x663E;&#x793A;&#x5BF9;&#x56FE;&#x50CF;&#x7684;&#x68C0;&#x6D4B;&#x7ED3;&#x679C;
            cv.imshow("result_win", frame)
            if (cv.waitKey(10) & 0xFF) == ord("q"):  # &#x68C0;&#x6D4B;&#x5230;q&#x6309;&#x952E;&#x5219;&#x9000;&#x51FA;
                break
        else:
            break
    cap.release()
    cv.destroyWindow("result_win")

< 示例三:训练人脸数据,并保存结果>

38、OpenCV之C++教程

每个S*文件夹存的是一个人的图像,每个人的图像采集十来张放在文件夹下。。

import os
import cv2 as cv
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
&#x6DFB;&#x52A0;plot&#x7684;&#x4E2D;&#x6587;&#x652F;&#x6301;
font = {'family': 'SimHei', 'weight': 'bold', 'size': 12}
plt.rc("font", **font)
&#x7A0B;&#x5E8F;&#x7684;&#x8FD0;&#x884C;&#x8D77;&#x70B9;&#x3001;main()
if __name__ == '__main__':
    targets = []  # &#x6BCF;&#x5F20;&#x56FE;&#x7247;&#x5BF9;&#x5E94;&#x7684;&#x59D3;&#x540D;ID
    faces_samples = []  # &#x6BCF;&#x5F20;&#x56FE;&#x7247;&#x63D0;&#x53D6;&#x7684;&#x4EBA;&#x8138;&#x77E9;&#x9635;
    faces_detect = cv.CascadeClassifier("haarcascade_frontalface_alt.xml")  # &#x52A0;&#x8F7D;&#x4EBA;&#x8138;&#x8BC6;&#x522B;&#x5668;
    imgRoot = "img_faces_src"
    imgPaths = [os.path.join(imgRoot, f) for f in os.listdir(imgRoot)]
    index = 0
    for imgPath in imgPaths:
        for imgFile in os.listdir(imgPath):  # &#x5FAA;&#x73AF;&#x6BCF;&#x4E2A;&#x6587;&#x4EF6;
            PIL_img = Image.open(os.path.join(imgPath, imgFile)).convert('L')  # &#x4EE5;&#x7070;&#x5EA6;&#x683C;&#x5F0F;&#x6253;&#x5F00;
            img_numpy = np.array(PIL_img, "uint8")  # &#x8F6C;&#x6362;&#x6210;np&#x683C;&#x5F0F;
            faces = faces_detect.detectMultiScale(img_numpy, scaleFactor=1.1, minNeighbors=5, minSize=(32, 32))  # &#x68C0;&#x6D4B;&#x4EBA;&#x8138;
            print(os.path.join(imgPath, imgFile), "len(faces) =", len(faces))
            for x, y, w, h in faces:
                s = img_numpy[y:y + h, x:x + w]
                s = cv.resize(s, dsize=(128, 128))
                targets.append(index)
                faces_samples.append(s)
        index = index + 1
    # &#x8BAD;&#x7EC3;&#x6570;&#x636E;&#x5E76;&#x4FDD;&#x5B58;&#x8BAD;&#x7EC3;&#x7ED3;&#x679C;
    recognizer = cv.face.LBPHFaceRecognizer_create()  # LBPH&#x8BAD;&#x7EC3;&#x5668;
    recognizer.train(faces_samples, np.array(targets))
    recognizer.write("trainer/trainer.yal")

< 示例四:使用训练好的人脸数据进行人脸识别>

import cv2 as cv
&#x7A0B;&#x5E8F;&#x7684;&#x8FD0;&#x884C;&#x8D77;&#x70B9;&#x3001;main()
if __name__ == '__main__':
    recogizer = cv.face.LBPHFaceRecognizer_create()
    recogizer.read("trainer/trainer.yal")
    face_detector = cv.CascadeClassifier("haarcascade_frontalface_alt.xml")
    cap = cv.VideoCapture(0)  # &#x8F93;&#x5165;0&#x6253;&#x5F00;&#x9ED8;&#x8BA4;&#x6444;&#x50CF;&#x5934;,&#x8F93;&#x5165;&#x89C6;&#x9891;&#x5730;&#x5740;&#x5219;&#x6253;&#x5F00;&#x89C6;&#x9891;&#x6587;&#x4EF6;
    if cap.isOpened():
        flag = True
    else:
        flag = False
    while flag:
        flag, frame = cap.read()
        if not flag:
            break
        frame = cv.flip(frame, 1)
        img_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)  # &#x56FE;&#x50CF;&#x8F6C;&#x4E3A;&#x7070;&#x5EA6;&#x56FE;
        face = face_detector.detectMultiScale(img_gray, scaleFactor=1.1, minNeighbors=5, minSize=(10, 10))
        for x, y, w, h in face:
            s = img_gray[y:y + h, x:x + w]
            s = cv.resize(s, dsize=(128, 128))
            ids, confidence = recogizer.predict(s)
            cv.rectangle(frame, (x, y), (x + w, y + w), color=(0, 0, 255), thickness=1)
            if confidence > 80:
                cv.putText(frame, "unknown" + ":%.2f" % confidence, (x + 10, y + 10), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
            else:
                cv.putText(frame, str(ids) + ":%.2f" % confidence, (x + 10, y + 10), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
        cv.imshow("re", frame)
        key = (cv.waitKey(20) & 0xFF)
        if key == ord('q'):  # &#x6309;q&#x952E;&#x9000;&#x51FA;
            break
    cv.destoryAllWindows()
    cap.release()

P1.33、基于FaceNet的人脸识别

FaceNet是一个识别率比较高的深度学习网络模型,当然用于人脸识别的网络有很多,这里推荐的是

38、OpenCV之C++教程

总结:paperswithcode是一个查找论文代码的网址,但并不是所有的论文代码都能找到,有些论文的数据集和代码是找不到的,只有论文上提供的方法,需要你自己去实现。

Original: https://blog.csdn.net/BaoTTing/article/details/120937058
Author: Bao@Ting
Title: 38、OpenCV之C++教程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/636944/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球