基于opencv-pyhton与opencv-c++的结合理解与学习
阅读原文时间:2023年08月28日阅读:1

2023年上半年,一直在学习opencv-c++版本,学习了其中的多个库函数

笔记链接:https://www.cnblogs.com/Tan-code/category/2339311.html

  • opencv-python 读取图片,画圆等基本操作 :
  • opencv-c++ 多个库函数:
  • opencv-python与opencv-c++ 结合理解:

结合两段代码来比较实现:

# 导入所需模块
import cv2
from matplotlib import pyplot as plt
import os
import numpy as np
# plt显示彩色图片
def plt_show0(img):
#cv2与plt的图像通道不同:cv2为[b,g,r];plt为[r, g, b]
    b,g,r = cv2.split(img)
    img = cv2.merge([r, g, b])
    plt.imshow(img)
    plt.show()

# plt显示灰度图片
def plt_show(img):
    plt.imshow(img,cmap='gray')
    plt.show()

# 图像去噪灰度处理
def gray_guss(image):
    image = cv2.GaussianBlur(image, (3, 3), 0)
    gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    return gray_image

# 读取待检测图片
origin_image = cv2.imread('E:\opencv_practice\licenses.jpg')
# 复制一张图片,在复制图上进行图像操作,保留原图
image = origin_image.copy()
# 图像去噪灰度处理
gray_image = gray_guss(image)
# x方向上的边缘检测(增强边缘信息)
Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
absX = cv2.convertScaleAbs(Sobel_x)
image = absX

# 图像阈值化操作——获得二值化图
ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU)
# 显示灰度图像
#plt_show(image)
# 形态学(从图像中提取对表达和描绘区域形状有意义的图像分量)——闭操作
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10))
image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX,iterations = 1)
# 显示灰度图像
#plt_show(image)

# 腐蚀(erode)和膨胀(dilate)
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1))
kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20))
#x方向进行闭操作(抑制暗细节)
image = cv2.dilate(image, kernelX)
image = cv2.erode(image, kernelX)
#y方向的开操作
image = cv2.erode(image, kernelY)
image = cv2.dilate(image, kernelY)
# 中值滤波(去噪)
image = cv2.medianBlur(image, 21)
# 显示灰度图像
#plt_show(image)
# 获得轮廓
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
width,height = 600,350  #所需图像大小

for item in contours:
    rect = cv2.boundingRect(item)
    x = rect[0]
    y = rect[1]
    weight = rect[2]
    height = rect[3]
    # 根据轮廓的形状特点,确定车牌的轮廓位置并截取图像,否则提取不到车牌轮廓
    if (weight > (height * 3.5)) and (weight < (height * 4)):
        image = origin_image[y:y + height, x:x + weight]

         # 将车牌图像进行透视变换,矫正为矩形形状
        pts1 = np.float32([[0, 0], [weight, 0], [0, height], [weight, height]])
        pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
        matrix = cv2.getPerspectiveTransform(pts1, pts2)
        warped_image = cv2.warpPerspective(image, matrix, (width, height))
        plt_show0(warped_image)
        cv2.imwrite('E://RM24暑假考核//rect//licenses.jpg',warped_image)

这是c++版的:

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

using namespace cv;
using namespace std;

void plt_show0(Mat img) {
    Mat bgr_img;
    cvtColor(img, bgr_img, COLOR_RGB2BGR);
    imshow("Image", bgr_img);
    waitKey(0);
}

void plt_show(Mat img) {
    imshow("Image", img);
    waitKey(0);
}

Mat gray_guss(Mat image) {
    Mat gray_image;
    GaussianBlur(image, image, Size(3, 3), 0);
    cvtColor(image, gray_image, COLOR_RGB2GRAY);
    return gray_image;
}

int main() {
    Mat origin_image = imread("E:\\opencv_practice\\licenses.jpg");

    Mat image = origin_image.clone();
    Mat gray_image = gray_guss(image);

    Mat Sobel_x,absX;
    Sobel(gray_image, Sobel_x, CV_16S, 1, 0);
    convertScaleAbs(Sobel_x,absX);
    image = absX;

    threshold(image, image, 0, 255, THRESH_OTSU);

    Mat kernelX = getStructuringElement(MORPH_RECT, Size(30, 10));
    morphologyEx(image,image, MORPH_CLOSE, kernelX);

    kernelX = getStructuringElement(MORPH_RECT, Size(50, 1));
    Mat kernelY = getStructuringElement(MORPH_RECT, Size(1, 20));
    dilate(image,image, kernelX);
    erode(image, image,kernelX);
    erode(image, image,kernelY);
    dilate(image, image,kernelY);

    medianBlur(image,image, 21);
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(image.clone(), contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    int width = 600;
    int height = 350;
    for (const auto& item : contours) {
        Rect rect = boundingRect(item);
        int x = rect.x;
        int y = rect.y;
        int weight = rect.width;
        int height = rect.height;

        if (weight > (height * 3.5) && weight < (height * 4)) {
            image = origin_image(Rect(x, y, weight, height));

            Mat pts1 = (Mat_<float>(4, 2) << 0, 0, weight, 0, 0, height, weight, height);
            Mat pts2 = (Mat_<float>(4, 2) << 0, 0, width, 0, 0, height, width, height);
            Mat matrix = getPerspectiveTransform(pts1, pts2);
            Mat warped_image;
            warpPerspective(image, warped_image, matrix, Size(width, height));
            plt_show0(warped_image);
            imwrite("E://RM24暑假考核//rect//licenses.jpg", warped_image);
        }
    }

    return 0;
}

上面两段代码是关于框出车牌的

个人观点:

python代码中,是不会提前声明一个变量的,而是用的时候直接 img = …

也就是说,绝大多数函数是有返回值的

而c++不同,许多函数 void function(InputArray,OutputArray,….) ,dstimg是直接写到API里的

但是有些函数还是有返回值的

像是代码中的:

Mat matrix = getPerspectiveTransform(pts1, pts2);
Rect rect = boundingRect(item);

这里还学到个新函数:

image = origin_image(Rect(x, y, weight, height));

这行代码是从原始图像(origin_image)中提取一个矩形区域(Rect)并保存到新的图像变量 image 中。Rect(x, y, width, height) 表示一个矩形,其中 (x, y) 是矩形的左上角坐标,width 是矩形的宽度,height 是矩形的高度。这样,origin_image(Rect(x, y, width, height)) 就表示从 origin_image 中裁剪出指定矩形区域的图像数据,并将其赋值给 image 变量。