C++ 和Python入门openCV

一 图像读取

Python 实现:

  1. 读取彩色图像
import cv2
img = cv2.imread("1.jpg")
cv2.imshow("pic_img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
  1. 读取灰度图像
import cv2
img = cv2.imread("1.jpg", 0)
cv2.imshow("pic_img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

C++实现:

#include
using namespace cv;
int main()
{
    cv:: Mat img = cv::imread("img/1.jpg");
    cv::imshow("pic_img", img);
    cv::waitKey(0);    
} // namespace cv;

编译运行:

g++ -g -o image_read image_read.cpp `pkg-config --cflags --libs opencv`
./image_read

二 图像写入

python实现

import numpy as np 
import cv2
img = np.empty((200, 200, 3), np.uint8)
img[:, :, 0] = 255
img[:, :, 1] = 0
img[:, :, 2] = 0
img = img[:, :, ::-1]
cv2.imshow("pic_write", img)
cv2.imwrite('save_img.jpg', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

C++实现:

#include
#include
using namespace cv;

int main(){
	cv::Mat img = cv::Mat(200, 200, CV_8UC3, cv::Scalar(255,0,0));
	for (int i; i<img.rows; i++){
		for (int j; j<img.cols; j++){
			img.at<cv::Vec3b>(i,j)[0]= 0;
			img.at<cv::Vec3b>(i,j)[1]= 0;
			img.at<cv::Vec3b>(i,j)[2]= 255;
		}
	}
	cv::imwrite("save_image.jpg",img);
}

c++实现方法二:

#include
#include
using namespace cv;
using namespace std;
int main(){
	cv::Mat img = cv::Mat(200, 200, CV_8UC3, cv::Scalar(255,0,0));
	std::vector<cv::Mat> ms;
	cv::split(img,ms);
	ms[1]=cv::Scalar(255);
	cv::merge(ms,img);
	cv::imshow("image",img);
	cv::waitKey(0);
	cv::imwrite("save_image.jpg",img);
}

编译运行:

g++ -g -o image_write image_write.cpp `pkg-config --cflags --libs opencv`
./image_write

三 视频和摄像头的调用

python实现:

import cv2
#读取视频
# #cap = cv2.VideoCapture("1.mp4")
#调用摄像头
cap = cv2.VideoCapture(0)
while True:
	#每执行一次读取一帧
    ret, frame = cap.read()
    cv2.imshow('frame', frame)
    if cv2.waitKey(30) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

C++实现:

#include
using namespace cv;

int main()
{
	cv::VideoCapture cap;
	cap = cv::VideoCapture(0);
	while (true){
		cv::Mat frame;
		cap >> frame;
		cv::imshow("frame", frame);
		cv::waitKey(30);
		}
		cap.release();
		cv::destroyAllWindows();
		
	}

编译运行:

g++ -g -o video_read video_read.cpp `pkg-config --cflags --libs opencv`
./video_read

四 截取部分图像数据

裁切想要的部分:
C++ 和Python入门openCV_第1张图片

import cv2
import numpy as np
img = cv2.imread("bird.jpg")
img = img[50:300, 145:278, :]
# b, g, r = cv2.split(img)
# img = cv2.merge((b, g, r))
cv2.imshow("img", img)
cv2.waitKey(0)

五 颜色通道提取

C++ 和Python入门openCV_第2张图片

import cv2
img = cv2.imread("bird.jpg")
b, g, r = cv2.split(img)
# 合并通道
img = cv2.merge((b, g, r))
cv2.imshow("img", img)

# 保留b 通道
img_b = img.copy()
img_b[..., 1] = 0
img_b[..., 2] = 0
cv2.imshow("b_channel", img_b)
# 保留g 通道
img_g = img.copy()
img_g[..., 0] = 0
img_g[..., 2] = 0
cv2.imshow("g_channel", img_g)
# 保留r 通道
img_r = img.copy()
img_r[..., 0] = 0
img_r[..., 1] = 0
cv2.imshow("r_channel", img_r)
cv2.waitKey(0)

六 色彩空间转换

python实现:

import cv2
img = cv2.imread(r"1.jpg")
# dst = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dst = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.imshow("img", img)
cv2.imshow("dst_image", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

C++实现:

#include

using namespace std;
int main(){
	cv::Mat img = cv::imread("img/1.jpg");
	cv::Mat dst;
	cv::cvtColor(img, dst, cv::COLOR_BGR2GRAY);
	//cv::cvtColor(img, dst, cv::COLO_BGR2HSV)
	cv::imshow("dst img", dst);
	cv::waitKey(0);
}

编译执行:

g++ -g -o color_space color_space.cpp `pkg-config --cflags --libs opencv`

利用色彩空间准换提取图片中的文字:
C++ 和Python入门openCV_第3张图片
C++ 和Python入门openCV_第4张图片
python 代码实现

import cv2
import numpy as np
img = cv2.imread("12.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_blue = np.array([1, 58, 20])
upper_blue = np.array([300, 400, 300])
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# res = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow('mask', mask)
# cv2.imshow("res", res)
cv2.waitKey(0)

七 边界填充

import cv2
img = cv2.imread("12.jpg")
top_size, bottom_size, left_size, right_size = (50, 50, 50, 50)
#复制法,也就是复制最边缘的像素
img1 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,
                         borderType = cv2.BORDER_REFLECT)

# 反射法(镜子) 比如: fedbce ———— ecbdefgh ———— ghfedbc
img2 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,
                         borderType=cv2.BORDER_REFLECT)

# 反射法,是以最边缘的像素为轴 gfedcb —— abcdefgh —— gfedcba
img3 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,
                         borderType=cv2.BORDER_REFLECT_101)

# 外包装法: cdefgh —— abcdefgh —— abcdefg
img4 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,
                         borderType=cv2.BORDER_WRAP)
# 常量法,用常树值填充
img5 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,
                         borderType=cv2.BORDER_CONSTANT)
cv2.imshow("img1", img1)
cv2.imshow("img2", img2)
cv2.imshow("img3", img3)
cv2.imshow("img4", img4)
cv2.imshow("img5", img5)
cv2.waitKey(0)

八 基本图形绘制

python 代码实现:

import cv2
import numpy as np

img = cv2.imread(r"15.jpg")

cv2.line(img, (100, 30), (210, 180), color=(0, 0, 255), thickness=2)
cv2.circle(img, (50, 50), 30, (0, 0, 255), 2)
cv2.rectangle(img, (100, 30), (210, 180), color=(0, 0, 255), thickness=2)
cv2.ellipse(img, (100, 100), (100, 50), 0, 0, 360, (255, 0, 0), 1)
#
pts = np.array([[10, 5], [50, 10], [70, 20], [20, 30]], np.int32)
pts = pts.reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, (0, 0, 255), 2)

cv2.putText(img, 'fang dong de mao ', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 1, lineType=cv2.LINE_AA)

cv2.imshow("pic show", img)
cv2.waitKey(0)

C++代码实现:

#include
using namespace std;

int main(){
	cv::Mat img = cv::imread("img/1.jpg");
	cv::line(img, cv::Point(100, 30), cv::Point(210, 180),cv::Scalar(0,0,255),2);
	cv::circle(img, cv::Point(50,50),30, cv::Scalar(0,0,255),2);
	cv::ellipse(img, cv::Point(100,300), cv::Point(210, 180), 0, 0, 360, cv::Scalar(0,0,255),2);
	cv::rectangle(img, cv::Point(100,300), cv::Point(210,180), cv::Scalar(0,0,255),2);

	std::vector<cv::Point> contour;
	contour.push_back(cv::Point(10,5));
	contour.push_back(cv::Point(50, 10));
	contour.push_back(cv::Point(70,20));
	contour.push_back(cv::Point(50,30));
	cv::polylines(img, contour, true, cv::Scalar(255,0,0),2, cv::LINE_AA);
	cv::putText(img, "fang dong de mao", cv::Point(10,30), cv::FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255),1,cv::LINE_AA);
	cv::imshow("img_show", img);
	cv::waitKey(0);
}

九 阈值操作

阈值操作在灰度图下进行

1. 二值化

a. OTSU二值化
C++ 和Python入门openCV_第5张图片
Python代码实现

import cv2
import numpy as np

img = cv2.imread("15.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
imgs = np.hstack((gray, binary))
cv2.imshow("img", imgs)
cv2.waitKey(0)

C++代码实现:

#include

int main(){
	cv::Mat img = cv::imread("img/15.jpg");
	cv::Mat gray;
	cv::Mat binary;
	cv::cvtColor(img,gray, cv::COLOR_BGR2GRAY);
	cv::threshold(gray,binary ,0., 255., cv::THRESH_BINARY | cv::THRESH_OTSU);
	cv::imshow("binary", binary);
	cv::waitKey(0);
}
2. 简单阈值
ret, binary = cv2.threshold(src, thresh, maxval, type)
"""
参数说明: 
sr: 输入图像,只能输入单通道图像,通常来说为灰度图像。
dst: 输出图
thresh: 阈值
maxval: 当像素值超过了阈值或小于阈值,所赋予的值
type: 二值化操作类型:
1. cv2.THRESH_BINARY 超过阈值部分取maxval(最大值)否则取0
2. cv2.THRESH_BINARY_INV 
3. cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
4. cv2.THRESH_TOZERO 大于阈值部分不改变,否则为0
5. cv2.THRESH_TOZERO_INV

"""

上面阈值操作原理如图:

C++ 和Python入门openCV_第6张图片
Python代码实现:

import cv2
import numpy as np

img = cv2.imread("15.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
# ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_TOZERO | cv2.THRESH_OTSU)
# ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_TOZERO_INV | cv2.THRESH_OTSU)
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_TRUNC | cv2.THRESH_OTSU)
imgs = np.hstack((gray, binary))
cv2.imshow("img", imgs)
cv2.waitKey(0)

C++代码实现:

#include

int main(){
	cv::Mat img = cv::imread("img/15.jpg");
	cv::Mat gray;
	cv::Mat binary;
	cv::cvtColor(img,gray, cv::COLOR_BGR2GRAY);
	//cv::threshold(gray,binary ,0., 255., cv::THRESH_BINARY | cv::THRESH_OTSU);
	//cv::threshold(gray,binary ,0., 255., cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
	//cv::threshold(gray,binary ,0., 255., cv::THRESH_TOZERO | cv::THRESH_OTSU);
	//cv::threshold(gray,binary ,0., 255., cv::THRESH_TOZERO_INV | cv::THRESH_OTSU);
	//cv::threshold(gray,binary ,0., 255., cv2.THRESH_TRUNC  | cv::THRESH_OTSU);
	cv::imshow("binary", binary);
	cv::waitKey(0);
}
3.自适应阈值

python代码实现:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('2.jpg', 0)
# 高斯模糊
# img = cv2.GaussianBlur(img, (5, 5), 0)

ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,
                            cv2.THRESH_BINARY, 11, 2)
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                            cv2.THRESH_BINARY, 11, 2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
          'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

C++代码实现:

#include

int main(){
	cv::Mat img = cv::imread("img/15.jpg", cv::IMREAD_GRAYSCALE);
	cv::Mat dst1, dst2;
	# 参数11 表示框的大小,一般选奇数。2为权重
	cv::adaptiveThreshold(img, dst1,  255., cv::ADAPTIVE_THRESH_MEAN_C, 
									cv::THRESH_BINARY, 11, 2);
	cv::adaptiveThreshold(img, dst2,  255., cv::ADAPTIVE_THRESH_GAUSSIAN_C, 
								cv::THRESH_BINARY,11,2);					
							
	cv::imshow("mean", dst1);
	cv::imshow("gaussian", dst2);
	cv::waitKey(0);
	}

效果图展示1:
C++ 和Python入门openCV_第7张图片

效果图展示2:
C++ 和Python入门openCV_第8张图片

4. 图像的平滑操作(即滤波操作)

C++ 和Python入门openCV_第9张图片

效果图:均值滤波 方框滤波 高斯滤波 中值滤波 双边滤波

C++ 和Python入门openCV_第10张图片
Python 代码实现:

import cv2
import numpy as np
src = cv2.imread(r"15.jpg")
# kernel = np.array([[1, 1, 0], [1, 0, -1], [0, -1, -1]], np.float32)  # 定义一个核
# dst = cv2.filter2D(src, -1, kernel=kernel)
dst = cv2.blur(src,(3,3)) # 相当于构建一个3*3卷积核,然后除以9取平均
box = cv2.boxFilter(src, -1, (3, 3), normalize=True)

# 高斯模糊的卷积核里的数值满足高斯分布,相当于更重视中间部分
gussian = cv2.GaussianBlur(src, (3, 3), 1)
# 从小到大排序,找到中间的值
median = cv2.medianBlur(src, 5)
# 双边滤波
double = cv2.bilateralFilter(src, 9, 75, 75)
img = np.hstack((src, dst, box, gussian, median, double))
cv2.imshow("src show", img)
# cv2.imshow("dst show", dst)
cv2.waitKey(0)

C++ 代码实现:

#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("2.jpg");
    cv::Mat dst;
    //自定义滤波
    //cv::Mat M = (cv::Mat_(3, 3) << 1, 1, 0, 1, 0, -1, 0, -1, -1);
   //cv::filter2D(img, dst, -1, M);
    //低通滤波
   // cv::blur(img, dst, cv::Size(3, 3));//均值滤波
   // cv::GaussianBlur(img, dst, cv::Size(3, 3),1,1);//高斯滤波
  // cv::medianBlur(img, dst, 3);//中值滤波
	//    cv::bilateralFilter(img, dst, 9, 75, 75);//双边滤波

    //高通滤波
	//cv::Laplacian(img, dst, -1, 1); //拉普拉斯滤波

    //求梯度
	// cv::Sobel(img, dst, -1, 1, 0);
    cv::Sobel(img, dst, -1, 0, 1);
	// cv::Scharr(img, dst, -1, 1, 0);
    cv::imshow("src", img);
    cv::imshow("dst", dst);
    cv::waitKey(0);
}
5. 锐化

USM算法
效果图:
C++ 和Python入门openCV_第11张图片

Python代码实现

import cv2
import numpy as np

img = cv2.imread("15.jpg")
img1 = cv2.GaussianBlur(img, (5, 5), 1) # 高斯滤波
img2 = cv2.addWeighted(img, 1.2, -1, 0, 0)
img3 = cv2.Laplacian(img1, -1, 1, 3, 1)
imgs = np.hstack((img, img1, img2, img3))
cv2.imshow("img", imgs)
cv2.waitKey(0)

C++代码实现:

#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("cmake-build-release/1.jpg");
    cv::Mat dst;
    cv::GaussianBlur(img, dst, cv::Size(5, 5), 0);//高斯滤波
    cv::addWeighted(img, 2, dst, -1, 0, dst);
    	//cv::Laplacian(img, dst, -1, 1); //拉普拉斯滤波
    cv::imshow("src", img);
    cv::imshow("dst", dst);
    cv::waitKey(0);
}

十 数值操作

1. 加减操作

Python代码实现

import cv2
import numpy as np
x = np.uint8([250])
y = np.uint8([10])
# 如果越界就取最大值255
print(cv2.add(x,y)) # 加
print(cv2.subtract(y,x)) # 减

C++ 代码实现

#include
using namespace std;
int main() {
    cv::Mat x = (cv::Mat_<uchar>(2, 1) << 250,34);
    cv::Mat y = (cv::Mat_<uchar>(2, 1) << 10,100);
    cv::Mat addrst, subrst;
    cv::add(x, y, addrst);
    cv::subtract(x, y, subrst); 
    cout << addrst << endl;
    cout << subrst << endl;
}

2. 按位运算

包含的按位操作有:与 或 非 异或 (AND OR NOT XOR)

在这里插入代码片

十一 图像融合

C++ 和Python入门openCV_第12张图片

import cv2
import numpy as np
img1 = cv2.imread('15.jpg')
img2 = cv2.imread('17.jpg')
# img1 = cv2.resize(img1, (300, 418))
# cv2.imwrite("17.jpg", img1)
#print(img1.shape)
#print(img2.shape)
# img = cv2.add(img1, img2)
dst = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)
img = np.hstack((img1, img2, dst))
cv2.imshow("img", img)
cv2.waitKey(0)
import cv2
import numpy as np
img1 = cv2.imread('19.jpg')
img2 = cv2.imread('17.jpg')
cv2.imshow("img1", img1)
cv2.imshow("img2", img2)
img = np.hstack((img1, img2))
cv2.imshow("img_original", img)

C++ 和Python入门openCV_第13张图片

rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols]
print(roi.shape)

img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
cv2.imshow("img3", mask_inv)

C++ 和Python入门openCV_第14张图片

img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
img2_fg = cv2.bitwise_and(img1, img2, mask=mask)
dst = cv2.add(img1_bg, img2_fg)
img1[0:rows, 0:cols] = dst
img1 = np.hstack((img1_bg, img2_fg))
cv2.imshow('img6', img1)
cv2.waitKey(0)

C++ 和Python入门openCV_第15张图片

十二 图像的几何变换

1. resize transpose flip

Python 代码实现

import cv2
img = cv2.imread("15.jpg")
img_resize = cv2.resize(img, (300, 300))
img_trans = cv2.transpose(img)
#镜像(上下)
# img_flip = cv2.flip(img, 0)
#镜像(左右)
img_flip = cv2.flip(img, 1)
cv2.imshow("img_resize", img_resize)
cv2.imshow("img_trans", img_trans)
cv2.imshow("img_flip", img_flip)
cv2.waitKey(0)

C++ 代码实现

#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("1.jpg");
    cv::Mat dst;
//  cv::resize(img, dst, cv::Size(300, 300));
//  cv::transpose(img, dst);
    cv::flip(img,dst,2);
    cv::imshow("src", img);
    cv::imshow("dst", dst);
    cv::waitKey(0);
}

2. 仿射变换

C++ 和Python入门openCV_第16张图片
仿射变换矩阵:
C++ 和Python入门openCV_第17张图片C++ 和Python入门openCV_第18张图片
变换效果:
C++ 和Python入门openCV_第19张图片

import cv2
import numpy as np
src = cv2.imread('1.jpg')
rows, cols, channel = src.shape

# M = np.float32([[1, 0, 50], [0, 1, 50]])
# M = np.float32([[0.5, 0, 0], [0, 0.5, 0]])
# M = np.float32([[-0.5, 0, cols // 2], [0, 0.5, 0]])
# M = np.float32([[1, 0.5, 0], [0, 1, 0]])
# 一般情况下难以获得仿射矩阵,可以调用这个函数生成一个矩阵,进行翻转 平移 变换
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 0.7)
# 仿射变换
dst = cv2.warpAffine(src, M, (cols, rows))
cv2.imshow('src pic', src)
cv2.imshow('dst pic', dst)

cv2.waitKey(0)

C++代码实现:

#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("1.jpg");
    cv::Mat M = (cv::Mat_<double>(2, 3) << 1, 0, 50, 0, 1, 50);
//    cv::Mat M = cv::getRotationMatrix2D(cv::Point(img.cols / 2, img.rows / 2), 45, 0.7);
    cv::Mat dst_img;
    cv::warpAffine(img, dst_img, M, img.size());
    cv::imshow("pic show", dst_img);
    cv::waitKey(0);
}

3. 透视变换

可以看到透视变换是把图片拉平的一个效果
C++ 和Python入门openCV_第20张图片

import cv2
import numpy as np

img = cv2.imread("2.jpg")
# 需要拉直的图片的四个点(这里选择了上面图片的 四个角的坐标)
pts1 = np.float32([[25, 30], [179, 25], [12, 188], [189, 190]])
# 需要将图片拉升到什么位置
pts2 = np.float32([[0, 0], [200, 0], [0, 200], [200, 200]])
# 透视变换
M = cv2.getPerspectiveTransform(pts1, pts2)
dst = cv2.warpPerspective(img, M, (200, 201))
cv2.imshow("src", img)
cv2.imshow("dst", dst)
cv2.waitKey(0)

C++代码实现:

#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("2.jpg");
    //Point2f 跟point类似
    cv::Point2f pts1[] = {cv::Point2f(25, 30), cv::Point2f(179, 25), cv::Point2f(12, 188), cv::Point2f(189, 190)};
    cv::Point2f pts2[] = {cv::Point2f(0, 0), cv::Point2f(200, 0), cv::Point2f(0, 200), cv::Point2f(200, 200)};
    cv::Mat M = cv::getPerspectiveTransform(pts1, pts2);
    cv::Mat dst_img;
    cv::warpPerspective(img, dst_img, M, img.size());
    cv::imshow("src", img);
    cv::imshow("dst", dst_img);
    cv::waitKey(0);
}

十三 图像形态学

处理前需要对图像进行二值化操作
C++ 和Python入门openCV_第21张图片在这里插入图片描述

1. 膨胀操作

  1. 膨胀操作可以让颜色值大的像素变得更粗。
  2. 膨胀操作前需要二值化图像

2. 腐蚀操作

与膨胀操作相反

3. 开操作

先腐蚀再膨胀
作用:去噪

4. 闭操作

先膨胀后腐蚀
作用:可以补漏洞

5. 梯度运算

梯度= 膨胀 - 腐蚀
作用:提取轮廓

6. 礼帽操作

礼帽操作= 原始图像 - 开运算结果
作用:获取噪点

7. 黑帽操作

黑帽操作 = 闭运算 - 原始图像
作用:获取漏洞

Python 代码实现

import cv2 as cv
import numpy as np
img = cv.imread("12.jpg", 0)

kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
dst1 = cv.dilate(img, kernel)  # 膨胀
dst2 = cv.erode(img, kernel) #腐蚀
dst3 = cv.morphologyEx(img, cv.MORPH_OPEN, kernel) #开
dst4 = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)  # 闭
dst5 = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)  # 梯度
dst6 = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel) # 顶帽
dst7 = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel) # 黑帽
#
img1 = np.hstack((dst1, dst2, dst3))
img2 = np.hstack((dst4, dst5, dst6, dst7))
cv.imshow('src', dst1)
cv.imshow("img", dst2)
# cv.imshow('dst', dst)
cv.waitKey(0)

C++代码实现:

#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("3.jpg");
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
    cv::Mat dst;
    cv::dilate(img, dst, kernel); //膨胀
//    cv::erode(img, dst, kernel);//腐蚀
//    cv::morphologyEx(img, dst, cv::MORPH_OPEN, kernel); //开
//    cv::morphologyEx(img, dst, cv::MORPH_CLOSE, kernel); //闭
//    cv::morphologyEx(img, dst, cv::MORPH_GRADIENT, kernel); //梯度
//    cv::morphologyEx(img, dst, cv::MORPH_TOPHAT, kernel); //顶帽
//    cv::morphologyEx(img, dst, cv::MORPH_BLACKHAT, kernel); //黑帽
    cv::imshow("src", img);
    cv::imshow("dst", dst);
    cv::waitKey(0);
}

十四 梯度算子

Sobel算子:是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度,梯度越大越有可能是边缘。Soble算子的功能集合了高斯平滑和微分求导,又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到的是图像在X方法与Y方向梯度图像。用此算子与原图像做卷积,可以检测出垂直方向的边缘。
C++ 和Python入门openCV_第22张图片C++ 和Python入门openCV_第23张图片

效果图:x 轴方向和y 轴方向
C++ 和Python入门openCV_第24张图片Python代码实现:

import cv2
import numpy as np

img = cv2.imread("2.jpg")
img_x = cv2.Sobel(img, -1, 1, 0)
img_y = cv2.Sobel(img, -1, 0, 1)
img_scharr_x = cv2.Scharr(img, -1, 1, 0)
img_scharr_y = cv2.Scharr(img, -1, 0, 1)

#  提高对比度
img = cv2.convertScaleAbs(img, alpha=6, beta=0)
imgs = np.hstack((img_x, img_y, img_scharr_x, img_scharr_y))
cv2.imshow("imgs", imgs)
cv2.waitKey(0)

C++代码实现:

#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("2.jpg");
    cv::Mat dst;
    //求梯度
//  cv::Sobel(img, dst, -1, 1, 0);
    cv::Sobel(img, dst, -1, 0, 1);
//  cv::Scharr(img, dst, -1, 1, 0);
    cv::Scharr(img, dst, -1, 0, 1);
    cv::imshow("src", img);
    cv::imshow("dst", dst);
    cv::waitKey(0);
}

十五 边缘检测(Canny 边缘检测)

1. 边缘检测原理:

C++ 和Python入门openCV_第25张图片

2. 非极大值抑制:它是一种边缘稀疏技术,非极大值抑制的作用在于瘦边。
  1. 将当前像素的梯度强度于沿正负方向上的两个像素进行比较。
  2. 如果当前像素的梯度强度与另外两个像素相比最大,则该像素点保留为边缘点,否则该像素点将被抑制。

C++ 和Python入门openCV_第26张图片

3. 双阈值边缘连接处理

C++ 和Python入门openCV_第27张图片C++ 和Python入门openCV_第28张图片
Canny 边缘检测效果展示:
C++ 和Python入门openCV_第29张图片
Python 代码实现:

import cv2
import numpy as np
img1 = cv2.imread("25.jpg", 0)
img2 = cv2.convertScaleAbs(img1, alpha=6, beta=0)
# img = cv2.GaussianBlur(img, (5, 5), 1)
img3 = cv2.medianBlur(img2, 5, 1)
canny1 = cv2.Canny(img3, 100, 150)
# canny = cv2.resize(canny1, dsize=(500, 500))
imgs = np.hstack((img1, img2, img3, canny1))
cv2.imshow('imgs', imgs)
cv2.waitKey(0)

C++ 代码实现:

#include
using namespace cv;
int main() {
    cv::Mat img = cv::imread("1.jpg",IMREAD_GRAYSCALE);
    cv::GaussianBlur(img, img, cv::Size(3, 3), 1);
    cv::Canny(img, img, 50, 150);
    cv::imshow("pic show", img);
    cv::waitKey(0);
}

十六 图像轮廓

1. 轮廓查找绘制

轮廓效果:
C++ 和Python入门openCV_第30张图片C++ 和Python入门openCV_第31张图片

import cv2

img = cv2.imread('14.jpg')
# cv2.imshow("src", img)
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imggray, 127, 255, 0)
# 查找轮廓, 参数cv2.CHAIN_APPROX_SIMPLE是找出关键的几个点
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#参数cv2.CHAIN_APPROX_NONE 找出多个点
# contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
print(len(contours[0]))
img_contour = cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
cv2.imshow("img_contour", img_contour)
cv2.waitKey(0)
#include

using namespace std;

int main() {
    cv::Mat img = cv::imread("14.jpg");
    cv::Mat gray_img, bin_img;
    cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY);
    cv::threshold(gray_img, bin_img, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> vec_4f;
    cv::findContours(bin_img, contours, vec_4f, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

    cv::drawContours(img, contours, -1, cv::Scalar(0,255,0), 2);

    cv::imshow("img_contour", img);
    cv::waitKey(0);
}
2. 圆心 周长 重心
import cv2
img = cv2.imread('26.jpg', 0)
ret, thresh = cv2.threshold(img, 127, 255, 0)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
M = cv2.moments(contours[0])  # 矩
cx, cy = int(M['m10'] / M['m00']), int(M['m01'] / M['m00'])
print("重心:", cx, cy)
area = cv2.contourArea(contours[0])
print("面积:", area)
perimeter = cv2.arcLength(contours[0], True)
print("周长:", perimeter)
#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("15.jpg");
    cv::Mat gray_img, bin_img;
    cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY);
    cv::threshold(gray_img, bin_img, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> vec_4f;
    cv::findContours(bin_img, contours, vec_4f, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
    cv::Moments M = cv::moments(contours[0]);  // 矩
    int cx = M.m10 / M.m00;
    int cy = M.m01 / M.m00;
    cout << "Focus:" << cx << " " << cy << endl;
    double area = cv::contourArea(contours[0]);
    cout << "area:" << area << endl;
    double arc_len = cv::arcLength(contours[0], true);
    cout << "arc_len:" << arc_len << endl;
    cv::drawContours(img, contours, -1, cv::Scalar(0,0,255), 2);
    cv::imshow("img_contour", img);
    cv::waitKey(0);
}
3. 轮廓近似

C++ 和Python入门openCV_第32张图片C++ 和Python入门openCV_第33张图片

import cv2

img = cv2.imread('26.jpg')
imggray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,127,255,0)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
epsilon = 40 #精度
epsilon = 0 #精度 图像本身的轮廓
approx = cv2.approxPolyDP(contours[0], epsilon, True)
img_contour= cv2.drawContours(img, [approx], -1, (0, 0, 255), 3)
cv2.imshow("img_contour", img_contour)
cv2.waitKey(0)
#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("15.jpg");
    cv::Mat gray_img, bin_img;
    cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY);
    cv::threshold(gray_img, bin_img, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> vec_4f;
    cv::findContours(bin_img, contours, vec_4f, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
    cv::approxPolyDP(contours.at(0), contours.at(0), 60, true);
    cv::drawContours(img, contours, -1, cv::Scalar(0, 0, 255), 2);
    cv::imshow("img_contour", img);
    cv::waitKey(0);
}
4. 凸包凸性检测

C++ 和Python入门openCV_第34张图片

import cv2

img = cv2.imread('15.jpg')
imggray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray, 127, 255, 0)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
hull = cv2.convexHull(contours[0])
print(cv2.isContourConvex(contours[0]), cv2.isContourConvex(hull))
#False True
#说明轮廓曲线是非凸的,凸包曲线是凸的
img_contour= cv2.drawContours(img, [hull], -1, (0, 0, 255), 3)
cv2.imshow("img_contour", img_contour)
cv2.waitKey(0)
#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("15.jpg");
    cv::Mat gray_img, bin_img;
    cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY);
    cv::threshold(gray_img, bin_img, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> vec_4f;
    cv::findContours(bin_img, contours, vec_4f, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
    vector<vector<cv::Point>> hull(contours.size());
    cv::convexHull(contours.at(0), hull.at(0));
    cout << cv::isContourConvex(contours.at(0))<<" "<<cv::isContourConvex(hull.at(0)) << endl;
    cv::drawContours(img, hull, -1, cv::Scalar(0, 0, 255), 2);
    cv::imshow("img_contour", img);
    cv::waitKey(0);
}
5. 边界检测

C++ 和Python入门openCV_第35张图片

import cv2
import numpy as np

img = cv2.imread('16.jpg')

imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imggray, 127, 255, 0)

contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 边界矩形
x, y, w, h = cv2.boundingRect(contours[0])
img_contour = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

# 最小矩形
rect = cv2.minAreaRect(contours[0])
box = cv2.boxPoints(rect)
box = np.int0(box)
img_contour = cv2.drawContours(img, [box], 0, (0, 0, 255), 2)

# 最小外切圆
(x, y), radius = cv2.minEnclosingCircle(contours[0])
center = (int(x), int(y))
radius = int(radius)
img_contour = cv2.circle(img, center, radius, (255, 0, 0), 2)

cv2.imshow("img_contour", img_contour)
cv2.waitKey(0)
#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("15.jpg");
    cv::Mat gray_img, bin_img;
    cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY);
    cv::threshold(gray_img, bin_img, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> vec_4f;
    cv::findContours(bin_img, contours, vec_4f, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
    // 边界矩形
    {
        cv::Rect rect = cv::boundingRect(contours[0]);
        cv::rectangle(img, cv::Point(rect.x, rect.y), cv::Point(rect.x + rect.width, rect.y + rect.height),
                      cv::Scalar(0, 255, 0), 2);
    }
    {
        cv::RotatedRect minRect = cv::minAreaRect(contours[0]);
        cv::Point2f vs[4];
        minRect.points(vs);
        std::vector<cv::Point> contour;
        contour.push_back(vs[0]);
        contour.push_back(vs[1]);
        contour.push_back(vs[2]);
        contour.push_back(vs[3]);
        cv::polylines(img, contour, true, cv::Scalar(255, 0, 0), 2, cv::LINE_AA);
    }
    {
        cv::Point2f center;
        float radius;
        cv::minEnclosingCircle(contours[0], center, radius);
        cv::circle(img, center, radius, cv::Scalar(255, 0, 0), 2);
    }
    cv::imshow("img_contour", img);
    cv::waitKey(0);
}
6. 轮廓的性质

C++ 和Python入门openCV_第36张图片C++ 和Python入门openCV_第37张图片
C++ 和Python入门openCV_第38张图片C++ 和Python入门openCV_第39张图片

对象的方向:

C++ 和Python入门openCV_第40张图片

import cv2
import numpy as np
img = cv2.imread('16.jpg')
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imggray, 127, 255, 0)
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 椭圆拟合
ellipse = cv2.fitEllipse(contours[0])
cv2.ellipse(img, ellipse, (255, 0, 0), 2)
# 直线拟合
h, w, _ = img.shape
[vx, vy, x, y] = cv2.fitLine(contours[0], cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((w - x) * vy / vx) + y)
cv2.line(img, (w - 1, righty), (0, lefty), (0, 0, 255), 2)
cv2.imshow("img_contour", img)
cv2.waitKey(0)
#include

using namespace std;

int main() {
    cv::Mat img = cv::imread("16.jpg");
    cv::Mat gray_img, bin_img;
    cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY);
    cv::threshold(gray_img, bin_img, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

    vector<vector<cv::Point>> contours;
    vector<cv::Vec4i> vec_4f;
    cv::findContours(bin_img, contours, vec_4f, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

//# 椭圆拟合
    cv::RotatedRect ellipse = cv::fitEllipse(contours[0]);
    cv::ellipse(img, ellipse, cv::Scalar(255, 0, 0), 2);

//# 直线拟合
    float w = img.size[0], h = img.size[1];
    cv::Vec4f line;
    cv::fitLine(contours[0], line, cv::DIST_L2, 0, 0.01, 0.01);
    float vx = line[0], vy = line[1], x = line[2], y = line[3];
    float lefty = (-x * vy / vx) + y;
    float righty = ((w - x) * vy / vx) + y;
    cv::line(img, cv::Point2f(w - 1, righty), cv::Point2f(0, lefty), cv::Scalar(0, 0, 255), 2);

    cv::imshow("img_contour", img);
    cv::waitKey(0);
}
形状匹配:
import cv2

img1 = cv2.imread('16.jpg', 0)
img2 = cv2.imread('17.jpg', 0)

ret, thresh = cv2.threshold(img1, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt1 = contours[0]

ret, thresh2 = cv2.threshold(img2, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt2 = contours[0]
# ret是匹配度,0是完全匹配,1是完全不匹配
ret = cv2.matchShapes(cnt1, cnt2, cv2.CONTOURS_MATCH_I2, 0.0)
print(ret)
#include
using namespace std;
int main() {
    cv::Mat img1 = cv::imread("16.jpg", cv::IMREAD_GRAYSCALE);
    cv::Mat img2 = cv::imread("17.jpg", cv::IMREAD_GRAYSCALE);
    cv::Mat bin_img1, bin_img2;
    vector<vector<cv::Point>> contours1, contours2;
    vector<cv::Vec4i> vec_4f_1, vec_4f_2;
    cv::threshold(img1, bin_img1, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    cv::findContours(bin_img1, contours1, vec_4f_1, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
    cv::threshold(img2, bin_img2, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    cv::findContours(bin_img2, contours2, vec_4f_2, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
    double ret = cv::matchShapes(contours1[0], contours2[0], cv::CONTOURS_MATCH_I2, 0.0);
    cout << ret << endl;
}

十七 图像金字塔

使用图像金字塔可以实现物体无缝融合

1. 高斯金字塔

a. 向上采样(放大操作)
b. 向下采样(缩小操作)

import cv2

img = cv2.imread(r"13.jpg")
for i in range(3):
    cv2.imshow(f"img{i}",img)
    # img = cv2.pyrDown(img)
    img = cv2.pyrUp(img)

cv2.waitKey(0)
#include
using namespace cv;
int main() {
    cv::Mat img = cv::imread("12.jpg");
    for (int i = 0; i < 3; i++) {
        cv::imshow("img" + i, img);
        cv::pyrDown(img,img);
//        cv::pyrUp(img, img);
    }
    cv::waitKey(0);
}

2. 拉普拉斯金字塔

import cv2

img = cv2.imread(r"12.jpg")
cv2.imshow("img", img)
img_down = cv2.pyrDown(img)
img_up = cv2.pyrUp(img_down)
cv2.imshow("net", img_up)
img_new = cv2.subtract(img, img_up)

#为了更容易看清楚,做了个提高对比度的操作
img_new = cv2.convertScaleAbs(img_new, alpha=5, beta=0)
cv2.imshow("img_LP", img_new)
cv2.waitKey(0)
#include
using namespace cv;
int main() {
    cv::Mat img = cv::imread("1.jpg");
    cv::Mat img_down, img_up, img_new;
    cv::pyrDown(img, img_down);
    cv::pyrUp(img_down, img_up);
    cv::subtract(img, img_up, img_new);
    cv::imshow("img_LP", img_new);
    cv::waitKey(0);
}

将两幅图片融合成一张图片:

C++ 和Python入门openCV_第41张图片

import cv2
import numpy as np

A = cv2.imread('21.jpg')
B = cv2.imread('22.jpg')

# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)

# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpB.append(G)

# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in range(5, 0, -1):
    GE = cv2.pyrUp(gpA[i])
    L = cv2.subtract(gpA[i - 1], GE)
    lpA.append(L)

# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in range(5, 0, -1):
    GE = cv2.pyrUp(gpB[i])
    L = cv2.subtract(gpB[i - 1], GE)
    lpB.append(L)

# Now add left and right halves of images in each level
LS = []
for i, (la, lb) in enumerate(zip(lpA, lpB)):
    rows, cols, dpt = la.shape
    ls = np.hstack((la[:, 0:cols // 2], lb[:, cols // 2:]))
    LS.append(ls)

# now reconstruct
ls_ = LS[0]
for i in range(1, 6):
    ls_ = cv2.pyrUp(ls_)
    ls_ = cv2.add(ls_, LS[i])
    # cv2.imshow(f"xxx{i}", ls_)

# image with direct connecting each half
real = np.hstack((A[:, :cols // 2], B[:, cols // 2:]))
imgs = np.hstack((ls_, real))

cv2.imshow('Pyramid_blending.jpg', ls_)
cv2.imshow('Pyramid_blending.jpg', imgs)
cv2.imshow('Direct_blending.jpg', real)

cv2.waitKey(0)

十九 直方图

1. 直方图

C++ 和Python入门openCV_第42张图片

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('1.jpg')
img[...,0]=0
img[...,1]=0
cv2.imshow("...",img)

# img_B = cv2.calcHist([img], [0], None, [256], [0, 256])
# plt.plot(img_B, label='B', color='b')

# img_G = cv2.calcHist([img], [1], None, [256], [0, 256])
# plt.plot(img_G, label='G', color='g')
#
img_R = cv2.calcHist([img], [2], None, [256], [0, 256])
plt.plot(img_R, label='R', color='r')

plt.show()
2. 直方图均衡化

可以去除图像的雾:
C++ 和Python入门openCV_第43张图片

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('7.jpg', 0)
his_1 = cv2.calcHist([img], [0], None, [255], [0, 255])
# 直方图均衡化
dst = cv2.equalizeHist(img)
his_2 = cv2.calcHist([dst], [0], None, [255], [0, 255])
# cv2.imwrite("15.jpg", dst)
#
plt.subplot(2, 2, 1)
plt.axis("off")
plt.title("original_img")
plt.imshow(img)
# plt.show()

plt.subplot(2, 2, 2)
plt.axis("off")
plt.title("original_hist")
plt.plot(his_1, label='his', color='r')
# plt.show()

plt.subplot(2, 2, 3)
plt.axis("off")
plt.title("equal_img")
plt.imshow(dst)
# plt.show()

plt.subplot(2, 2, 4)
plt.axis("off")
plt.title("equal_hist")
plt.plot(his_2, label='his', color='b')
plt.show()
#include
using namespace std;
int main() {
    cv::Mat img = cv::imread("7.jpg", cv::IMREAD_GRAYSCALE);
    cv::Mat dst;
    cv::equalizeHist(img, dst);
    cv::imshow("dst", dst);
    cv::waitKey(0);
}
3. 自适应直方图均衡化

import cv2

img = cv2.imread('8.jpg', 0)
cv2.imshow("src", img)
# 普通的直方图均衡化
dst1 = cv2.equalizeHist(img)
cv2.imshow("dst1", dst1)

# 自适应直方图均衡化
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
dst2 = clahe.apply(img)
cv2.imshow("dst2", dst2)

cv2.waitKey(0)
4. 直方图反向投影

根据颜色来提取物体,说简单点就是有两张图,一张图片是下面第一张图片,另一张图片是图片中草坪的那部分,然后计算机会根据给出的草坪来找出第一张图片中的草坪。(下面提取足球场的草坪)
C++ 和Python入门openCV_第44张图片

import cv2
import numpy as np

roi = cv2.imread('10.jpg')
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
target = cv2.imread('9.jpg')
hsvt = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)

roihist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

cv2.normalize(roihist, roihist, 0, 255, cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsvt], [0, 1], roihist, [0, 180, 0, 256], 1)

disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
dst = cv2.filter2D(dst, -1, disc)

ret, thresh = cv2.threshold(dst, 50, 255, 0)

thresh = cv2.merge((thresh, thresh, thresh))

res = cv2.bitwise_and(target, thresh)
res = np.hstack((target, thresh, res))

cv2.imshow('img', res)
cv2.waitKey(0)

二十 傅立叶变换

傅立叶变换就是多个正余弦波叠加可以用来近似任何一个原始的周期函数,它实质是将时域函数转换到频域。 而其中时域就是永远随着时间的变化而变化的,而频域就是装着正余弦波的空间,代表着每一条正余弦波的幅值,而表示正余弦波除了幅值是不够的,就还有相位谱。
该图来源:https://baijiahao.baidu.com/s?id=1636833728798493906&wfr=spider&for=pc
C++ 和Python入门openCV_第45张图片

1. 傅里叶变换用Opencv实现:

这里保存低频信号使图像模糊:
C++ 和Python入门openCV_第46张图片

  1. cv2.dft(img, cv2.DFT_COMPLEX_OUTPUT) 进行傅里叶变化
    cv2.DFT_COMPLEX_OUTPUT表示进行傅里叶变化的方法
  2. np.fft.fftshift(img) 将图像中的低频部分移动到图像的中心
  3. cv2.magnitude(x, y) 将sqrt(x^2 + y^2) 计算矩阵维度的平方根
    参数说明:需要进行x和y平方的数
    4.np.fft.ifftshift(img) # 进图像的低频和高频部分移动到图像原来的位置

参数说明:img表示输入的图片

5.cv2.idft(img) # 进行傅里叶的逆变化

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('9.jpg', 0)

dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))

plt.figure(figsize=(10, 10))
plt.subplot(221), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(magnitude_spectrum, cmap='gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])

rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow - 30:crow + 30, ccol - 30:ccol + 30] = 1
fshift = dft_shift * mask
# apply mask and inverse DFT

f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])

plt.subplot(223), plt.imshow(img_back, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(224), plt.imshow(img_back)
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])

plt.show()

2. 傅立叶变换用numpy实现:

这里去掉高频信息保留低频信息,得到了人的轮廓,去除了背景。
C++ 和Python入门openCV_第47张图片

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('9.jpg', 0)

f = np.fft.fft2(img) #傅里叶变换
fshift = np.fft.fftshift(f) #把中点移动到中间去

magnitude_spectrum = 20 * np.log(np.abs(fshift)) #计算每个频率的成分多少

plt.figure(figsize=(10, 10))
plt.subplot(221), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(magnitude_spectrum, cmap='gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])

#去掉低频信号,留下高频信号
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
fshift[crow - 30:crow + 30, ccol - 30:ccol + 30] = 0


#傅里叶逆变换
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.abs(img_back)

plt.subplot(223), plt.imshow(img_back, cmap='gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(224), plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])

plt.show()

你可能感兴趣的:(openCV)