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<opencv2/opencv.hpp>
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<opencv2/opencv.hpp>
#include<vector>
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<opencv2/opencv.hpp>
#include<vector>
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<opencv2/opencv.hpp>
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

四 截取部分圖像數據

裁切想要的部分:
在這裏插入圖片描述

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)

五 顏色通道提取

在這裏插入圖片描述

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<opencv2/opencv.hpp>

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`

利用色彩空間準換提取圖片中的文字:
在這裏插入圖片描述
在這裏插入圖片描述
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<opencv2/opencv.hpp>
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二值化
在這裏插入圖片描述
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<opencv2/opencv.hpp>

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

"""

上面閾值操作原理如圖:

在這裏插入圖片描述
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<opencv2/opencv.hpp>

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<opencv2/opencv.hpp>

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:
在這裏插入圖片描述

效果圖展示2:
在這裏插入圖片描述

4. 圖像的平滑操作(即濾波操作)

在這裏插入圖片描述

效果圖:均值濾波 方框濾波 高斯濾波 中值濾波 雙邊濾波
在這裏插入圖片描述
在這裏插入圖片描述
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<opencv2/opencv.hpp>
using namespace std;
int main() {
    cv::Mat img = cv::imread("2.jpg");
    cv::Mat dst;
    //自定義濾波
    //cv::Mat M = (cv::Mat_<double>(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算法
效果圖:
在這裏插入圖片描述

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<opencv2/opencv.hpp>
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<opencv2/opencv.hpp>
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)

在這裏插入代碼片

十一 圖像融合

在這裏插入圖片描述

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)

在這裏插入圖片描述

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)

在這裏插入圖片描述

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)

在這裏插入圖片描述

十二 圖像的幾何變換

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<opencv2/opencv.hpp>
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. 仿射變換

在這裏插入圖片描述
仿射變換矩陣:
在這裏插入圖片描述在這裏插入圖片描述
變換效果:
在這裏插入圖片描述

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<opencv2/opencv.hpp>
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. 透視變換

可以看到透視變換是把圖片拉平的一個效果
在這裏插入圖片描述

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<opencv2/opencv.hpp>
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);
}

十三 圖像形態學

處理前需要對圖像進行二值化操作
在這裏插入圖片描述在這裏插入圖片描述

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<opencv2/opencv.hpp>
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方向梯度圖像。用此算子與原圖像做卷積,可以檢測出垂直方向的邊緣。
在這裏插入圖片描述在這裏插入圖片描述

效果圖:x 軸方向和y 軸方向
在這裏插入圖片描述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<opencv2/opencv.hpp>
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. 邊緣檢測原理:

在這裏插入圖片描述

2. 非極大值抑制:它是一種邊緣稀疏技術,非極大值抑制的作用在於瘦邊。
  1. 將當前像素的梯度強度於沿正負方向上的兩個像素進行比較。
  2. 如果當前像素的梯度強度與另外兩個像素相比最大,則該像素點保留爲邊緣點,否則該像素點將被抑制。

在這裏插入圖片描述

3. 雙閾值邊緣連接處理

在這裏插入圖片描述在這裏插入圖片描述
Canny 邊緣檢測效果展示:
在這裏插入圖片描述
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<opencv2/opencv.hpp>
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. 輪廓查找繪製

輪廓效果:
在這裏插入圖片描述在這裏插入圖片描述

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<opencv2/opencv.hpp>

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<opencv2/opencv.hpp>
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. 輪廓近似

在這裏插入圖片描述在這裏插入圖片描述

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<opencv2/opencv.hpp>
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. 凸包凸性檢測

在這裏插入圖片描述

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<opencv2/opencv.hpp>
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. 邊界檢測

在這裏插入圖片描述

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<opencv2/opencv.hpp>
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. 輪廓的性質

在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述

對象的方向:

在這裏插入圖片描述

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<opencv2/opencv.hpp>

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<opencv2/opencv.hpp>
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<opencv2/opencv.hpp>
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<opencv2/opencv.hpp>
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);
}

將兩幅圖片融合成一張圖片:

在這裏插入圖片描述

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. 直方圖

在這裏插入圖片描述

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. 直方圖均衡化

可以去除圖像的霧:
在這裏插入圖片描述

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<opencv2/opencv.hpp>
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. 直方圖反向投影

根據顏色來提取物體,說簡單點就是有兩張圖,一張圖片是下面第一張圖片,另一張圖片是圖片中草坪的那部分,然後計算機會根據給出的草坪來找出第一張圖片中的草坪。(下面提取足球場的草坪)
在這裏插入圖片描述

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
在這裏插入圖片描述

1. 傅里葉變換用Opencv實現:

這裏保存低頻信號使圖像模糊:
在這裏插入圖片描述

  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實現:

這裏去掉高頻信息保留低頻信息,得到了人的輪廓,去除了背景。
在這裏插入圖片描述

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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章