- 视频读取
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main() {
VideoCapture cap;
cap.open("D:/opencv/opencv/sources/samples/data/vtest.avi");
if (!cap.isOpened())
return -1;
int width = cap.get(CV_CAP_PROP_FRAME_WIDTH); // 宽度
int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);// 高度
int frameRate = cap.get(CV_CAP_PROP_FPS); // 帧率
int totalFrames = cap.get(CV_CAP_PROP_FRAME_COUNT); // 帧数
cout << "视频宽度=" << width << endl;
cout << "视频高度=" << height << endl;
cout << "视频帧率=" << frameRate << endl;
cout << "视频帧数=" << totalFrames << endl;
Mat frame,dst;
while (1) {
cap >> frame;
if (frame.empty())
break;
//imshow("video", frame);
Canny(frame, dst, 20, 180);
imshow("video", dst);
waitKey(20);
}
cap.release();
return 0;
}
# 鼠标左键点下,画圆
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
void OnMouse(int event,int x,int y,int flags,void * param)
{
Mat img = *(Mat*)param;
if (event == CV_EVENT_LBUTTONDOWN)
{
cout << "Mouse down" << endl;
circle(img, Point(x, y), 20, Scalar(255, 0, 0), 2, 8);
}
}
int main() {
Mat img(500,500,CV_8UC3,Scalar(255,255,255));
namedWindow("Mouse", CV_WINDOW_AUTOSIZE);
setMouseCallback("Mouse", OnMouse, &img);
while(1) {
imshow("Mouse", img);
if (27 == waitKey(10))//安下Esc 退出
break;
}
return 0;
}
# 鼠标左键拖动两个点,画矩形
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Point pt;
void OnMouse(int event,int x,int y,int flags,void * param)
{
Mat img = *(Mat*)param;
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
pt.x = x;
pt.y = y;
break;
case CV_EVENT_LBUTTONUP:
rectangle(img, pt, Point(x, y), Scalar(255, 0, 0), 2, 8);
break;
default:
break;
}
}
int main() {
Mat img(500,500,CV_8UC3,Scalar(255,255,255));
namedWindow("Mouse", CV_WINDOW_AUTOSIZE);
setMouseCallback("Mouse", OnMouse, &img);
while(1) {
imshow("Mouse", img);
if (27 == waitKey(10))//安下Esc 退出
break;
}
return 0;
}
# 调用canny算子进行边缘检测,滑动窗口改变的是canny算子的下限值
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int value = 0;
void OnChange(int event,void * param)
{
Mat src = *(Mat*)param,dst;
//threshold(src, dst, value, 255, THRESH_BINARY);
Canny(src, dst, value, 255);
imshow("TrackBar", dst);
}
int main() {
Mat src = imread("F:/12.jpg",0),dst;
namedWindow("TrackBar",CV_WINDOW_AUTOSIZE);
createTrackbar("Threshold","TrackBar",&value,255,OnChange,&src);
threshold(src, dst, value, 255, THRESH_BINARY);
imshow("TrackBar", dst);
waitKey(0);
return 0;
}
# 鼠标截图功能,读取图片,在图片中框选ROI区域,并将ROI区域重新保存为一张.bmp图片
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat src = imread("F:/12.jpg", 1); // 读取图片
Point pt; //保存鼠标左键按下时的点
bool flag_1 = false; //当鼠标左键按下时,为真
Mat temp = src.clone(); //记录原图,用于后续刷新框图
Mat ROI;
// 鼠标消息回调函数
void OnMouse(int event,int x,int y,int flag,void * param)
{
//Mat src = *(Mat*)param,dst;
//Mat temp = src.clone();
switch (event)
{
case CV_EVENT_LBUTTONDOWN: //鼠标左键按下
flag_1 = true;
pt.x = x;
pt.y = y;
break;
case CV_EVENT_MOUSEMOVE: //鼠标移动
if (flag_1)
{
temp.copyTo(src);
rectangle(src, pt, Point(x, y), Scalar(0, 255, 0), 2, 8);
}
break;
case CV_EVENT_LBUTTONUP: //鼠标左键抬起
rectangle(src, pt, Point(x, y), Scalar(0, 255, 0), 2, 8);
flag_1 = false;
ROI = temp(Rect(pt.x, pt.y, x - pt.x, y - pt.y)); //确定ROI区域
imshow("ROI", ROI);
imwrite("ROI.bmp", ROI);
break;
default:
break;
}
}
int main() {
//Mat src = imread("F:/12.jpg",1),dst;
namedWindow("TrackBar",CV_WINDOW_AUTOSIZE);
setMouseCallback("TrackBar",OnMouse,&src);
while (1)
{
imshow("TrackBar", src);
if (27 == waitKey(10))
break;
}
return 0;
}
# 滑动条视频播放
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
double Fps;
int value = 0; //设置进度条时传递的参数,此时指从哪一帧开始
int framePos;
void OnChange(int,void* )
{
}
int main() {
Mat frame;
char strFps[20];
VideoCapture cap("vtest.avi");
int FrameCount = cap.get(CV_CAP_PROP_FRAME_COUNT); //获取视频总帧数
Fps = cap.get(CV_CAP_PROP_FPS); // 获取视频原始帧率
if (!cap.isOpened()) //如果视频打开失败,则返回
return -1;
namedWindow("Video",CV_WINDOW_AUTOSIZE);
createTrackbar("Frame", "Video", &value, FrameCount, OnChange, 0);
sprintf_s(strFps,"Fps:%0.1lf/s", Fps);
while (1)
{
framePos = cap.get(CV_CAP_PROP_POS_FRAMES);//获取视频当前帧
setTrackbarPos("Frame","Video", framePos); //设置滑动条位置
cap >> frame;
if (frame.empty()) //图片读取为空,则结束
break;
putText(frame, strFps, Point(5, 30),CV_FONT_HERSHEY_COMPLEX_SMALL, 1, Scalar(0, 255, 0), 1, 8);
imshow("Video", frame);
if (27 == (int)waitKey(1000 / Fps)) // 按下Esc退出
break;
}
cap.release();
destroyAllWindows();
return 0;
}
# 滑动条调节对比度和亮度
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#define WIN_NAME "结果图"
int Contrase_Value = 20; //对比度
int Bright_Value = 20; //亮度
Mat src;
Mat dst;
void OnChange(int ,void*)
{
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
dst.at<Vec3b>(i,j)[0] = saturate_cast<uchar>(src.at<Vec3b>(i,j)[0] * 0.01*Contrase_Value + Bright_Value);
dst.at<Vec3b>(i,j)[1] = saturate_cast<uchar>(src.at<Vec3b>(i,j)[1] * 0.01*Contrase_Value + Bright_Value);
dst.at<Vec3b>(i,j)[2] = saturate_cast<uchar>(src.at<Vec3b>(i,j)[2] * 0.01*Contrase_Value + Bright_Value);
}
}
imshow("原图", src);
imshow(WIN_NAME, dst);
}
int main()
{
src = imread("F:/12.jpg");
dst=Mat::zeros(src.size(),src.type()); //以输入图像的大小和类型构建全零矩阵
namedWindow(WIN_NAME,CV_WINDOW_AUTOSIZE);
createTrackbar("对比度",WIN_NAME, &Contrase_Value,300,OnChange,0);
createTrackbar("亮度",WIN_NAME, &Bright_Value,200,OnChange,0);
OnChange(Contrase_Value,0);
OnChange(Bright_Value,0);
waitKey(0);
}
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src;
Mat dst;
src = imread("F:/12.jpg");
vector<Mat> channels;
split(src, channels); //通道分离
Mat bluechannel = channels.at(0); //蓝色通道
Mat greenchannel = channels.at(1); //绿色通道
Mat redchannel = channels.at(2); //红色通道
threshold(bluechannel, bluechannel , 200, 255, THRESH_BINARY);
threshold(greenchannel, greenchannel, 200, 255, THRESH_BINARY);
threshold(redchannel, redchannel, 200, 255, THRESH_BINARY);
//imshow("blue", bluechannel);
//imshow("green", greenchannel);
//imshow("red", redchannel);
merge(channels, dst); //合并通道
imshow("dst",dst);
waitKey(0);
}
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src;
Mat dst;
src = imread("F:/12.jpg");
Mat logo = imread("D:/opencv/opencv/sources/samples/data/opencv-logo.png");
Mat mask = Mat::zeros(logo.size(),CV_8UC1); // 先创建一个纯黑图
circle(mask, Point(mask.rows / 2, mask.cols / 2),100,Scalar(255),-1,8); // 画一个填充的半径为100的圆
Mat imgRoi = src(Rect(20,3,logo.cols,logo.rows));//Rect方法定义,x,y,w,h
//Mat imgRoi = src(Range(300,700),Range(200,1100));//Range方法定义
logo.copyTo(imgRoi,mask);//将logo图片拷贝到img的ROI上(注意copyTo函数要求两图像大小和类型都相同,否则无效)
//1、image.copyTo(imageROI),作用是把image的内容粘贴到imageROI;
// 2、image.copyTo(imageROI,mask),作用是把mask和image重叠以后
//把mask中像素值为0(black)的点对应的image中的点变为透明,而保留其他点。
imshow("roi", src);
//imwrite("saveRoi.png", imgRoi);//保存ROI图片
waitKey(0);
}
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src;
Mat dst;
src = imread("F:/12.jpg");
Mat logo = imread("D:/opencv/opencv/sources/samples/data/opencv-logo.png");
Mat mask = imread("D:/opencv/opencv/sources/samples/data/opencv-logo.png");
bitwise_not(mask, mask); //将logo图片取反,因为logo图背景为白色,要变成掩码用的黑色,则需要取反
threshold(mask, mask, 100, 255, THRESH_BINARY); // 利用二值化,将背景都直为0
//Mat mask = Mat::zeros(logo.size(),CV_8UC1); // 先创建一个纯黑图
//circle(mask, Point(mask.rows / 2, mask.cols / 2),100,Scalar(255),-1,8); // 画一个填充的半径为100的圆
Mat imgRoi = src(Rect(20,3,logo.cols,logo.rows));//Rect方法定义,x,y,w,h
//Mat imgRoi = src(Range(300,700),Range(200,1100));//Range方法定义
logo.copyTo(imgRoi,mask);//将logo图片拷贝到img的ROI上(注意copyTo函数要求两图像大小和类型都相同,否则无效)
//1、image.copyTo(imageROI),作用是把image的内容粘贴到imageROI;
// 2、image.copyTo(imageROI,mask),作用是把mask和image重叠以后
//把mask中像素值为0(black)的点对应的image中的点变为透明,而保留其他点。
imshow("roi", src);
//imwrite("saveRoi.png", imgRoi);//保存ROI图片
waitKey(0);
}
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src;
Mat dst;
src = imread("F:/12.jpg");
//resize(src, dst, Size(500, 300)); // 通过Size参数设置图片大小
resize(src, dst, Size(),0.5,0.5); //通过比例系数设置图像大小,Size()设置为默认参数
imshow("src", src);
imshow("dst", dst);
waitKey(0);
}
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src;
Mat dst;
src = imread("F:/12.jpg");
Point2f center = Point2f(src.rows / 2, src.cols / 2); //旋转中心
double angle = 45; //旋转角度
double scale = 0.5; //缩放尺度
Mat rotateMat;
rotateMat = getRotationMatrix2D(center, angle, scale); //生成二维旋转矩阵
Mat rotateImg;
warpAffine(src, rotateImg, rotateMat, Size(1200, 900)); //调用仿射变换函数
imshow("src", src);
imshow("dst", rotateImg);
waitKey(0);
}
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat src;
Mat dst1,dst2;
src = imread("F:/12.jpg");
Mat element = getStructuringElement(MORPH_RECT,Size(9,9));
erode(src,dst1,element); // 腐蚀
dilate(src,dst2, element); // 膨胀
imshow("src", src);
imshow("腐蚀", dst1);
imshow("膨胀", dst2);
waitKey(0);
}
2. python
2.1 模糊操作
均值滤波 dst = blur(src,ksize,anchor=None,borderType=None)
-参数src表示输入图像
-参数dst 表示模糊之后输出对象
-参数ksize表示卷积核大小,此参数决定模糊程度,Size(x, y)其中x, y取值越大表现模糊程度越深,而且X与Y的值为奇数。
-参数anchor表示锚定的位置,也就是卷积核替换重叠像素中的哪个位置。此参数一般使用Point(-1,-1)表示使用卷积核的中心位置。
-最后一个参数borderType表示对边缘的处理方法,一般默认4表示默认处理方法
blurDst = cv2.blur(src,(3,3))
# (ncols, nrows)
高斯滤波dst = cv2.GaussianBlur(src,ksize,SigmaX,SigmaY=None,borderType=None);
-参数src表示输入图像
-参数dst 表示模糊之后输出对象
-参数ksize表示卷积核大小,此参数决定模糊程度,Size(x, y)其中x, y取值越大表现模糊程度越深,而且X与Y的值为奇数。
-参数SigmaX表示高斯方程中X方向的标准方差
-参数SigmaY表示高斯方程中X方向的标准方差
-最后一个参数表示对边缘的处理方法,一般默认4表示默认处理方法
blurDst = cv2.GaussianBlur(src,(3,3),11,11);
# (ncols, nrows)
中值滤波dst = cv2.medianBlur(src,ksize)
-参数src表示输入图像
-参数dst 表示模糊之后输出对象
-参数ksize表示卷积核大小,必须是正数而且必须是大于1,如:3、5、7等。
blurDst = cv2.medianBlur(src,(3,3))
# (ncols, nrows)
双边滤波dst = cv2.bilateralFilter(src,d,sigmaColor,sigmaSpace,borderType=None)
-参数src表示输入图像
-参数dst 表示模糊之后输出对象
-参数d表示双边滤波时候中心到周围像素距离
-参数sigmaColor表示高斯核中颜色值标准方差
-参数sigmaSpace表示高斯核中空间的标准方差
-参数borderType表示边缘的处理方法
blurDst = cv2.bilateralFilter(src,15,120,10,4)
# (ncols, nrows)
均值偏移滤波dst=cv2.pyrMeanShiftFiltering( src, sp, sr, maxLevel=1, TermCriteria termcrit=TermCriteria( TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) );
src,输入图像
dst,输出图像
sp,定义的漂移物理空间半径大小
sr,定义的漂移色彩空间半径大小
maxLevel,定义金字塔的最大层数
termcrit,定义的漂移迭代终止条件,可以设置为迭代次数满足终止,迭代目标与中心点偏差满足终止,或者两者的结合
im = cv2.pyrMeanShiftFiltering(src, 10, 50)
滤波函数filter2D
-参数src表示输入图像
-参数dst表示模糊之后输出对象
-参数d表输出图像的深度,-1表示跟输入图像深度相同。
-参数kernel表示自定义的卷积核或者算子。
-参数anchor表示锚定的位置,Point(-1, -1)表示默认为卷积核中心位置。
-参数delta表示卷积处理之后的每个像素值是否加上常量delta,默认0.0表示不加上额外值到处理后的像素值上。
-参数borderType表示边缘像素的处理方式,默认为BORDER_DEFAULT。
通过定义不同的卷积核、filter2D函数可以实现卷积的各种功能、包括模糊、锐化、边缘提取等。
kernel = np.ones([3, 3], dtype=np.float32)/9
cv2.filter2D(src,-1,kernel);
3. 直方图统计
3.1 利用opencv自带函数
hist = cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]])
imaes:输入的图像
channels:选择图像的通道
mask:掩膜,是一个大小和image一样的np数组,其中把需要处理的部分指定为1,不需要处理的部分指定为0,一般设置为None,表示处理整幅图像
histSize:使用多少个bin(柱子),一般为256
ranges:像素值的范围,一般为[0,255]表示0~255
后面两个参数基本不用管。
注意,除了mask,其他四个参数都要带[]号。
img = cv2.imread('cat.jpg',0) #0表示灰度图
hist = cv2.calcHist([img],[0],None,[256],[0,256])
hist.shape
#(256, 1)
# 统计每个通道的直方图
img = cv2.imread('cat.jpg')
color = ('b','g','r')
for i,col in enumerate(color):
histr = cv2.calcHist([img],[i],None,[256],[0,256])
plt.plot(histr,color = col)
plt.xlim([0,256])
plt.show()
# 在mask下统计直方图
# 创建mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
img = cv2.imread('cat.jpg', 0)
masked_img = cv2.bitwise_and(img, img, mask=mask)#与操作
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0, 256])
plt.show()
3.2 利用matplotlib.pyplot 的函数
img = cv2.imread('clahe.jpg',0) #0表示灰度图
plt.hist(img.ravel(),256);
plt.show()
equ = cv2.equalizeHist(img) # 直方图均衡化
plt.hist(equ.ravel(),256)
plt.show()
numpy中的ravel()、flatten()、squeeze()都有将多维数组转换为一维数组的功能,区别:
ravel():如果没有必要,不会产生源数据的副本
flatten():返回源数据的副本
squeeze():只能对维数为1的维度降维
3.3 局部自适应均衡化
全局的均衡化也会存在一些问题,由于整体亮度的提升,会使得局部图像的细节变得模糊;因此可以使用效果更好的自适应均衡化。
cv2.createCLAHA(clipLimit=8.0, titleGridSize=(8, 8)) 用于生成自适应均衡化图像
clipLimit颜色对比度的阈值
titleGridSize进行像素均衡化的网格大小,即在多少网格下进行直方图的均衡化操作
# 使用自适应直方图均衡化
# 第一步:实例化自适应直方图均衡化函数
img = cv2.imread('clahe.jpg',0) #0表示灰度图
clahe = cv2.createCLAHE(clipLimit=2.0,
tileGridSize=(8, 8))
# 第二步:进行自适应直方图均衡化
clahe = clahe.apply(img)
# 第三步:进行图像的展示
cv2.imshow('imgs', np.hstack((img, clahe)))
cv2.waitKey(0)
cv2.destroyAllWindows()
4. 金字塔(上采样、下采样)
高斯金字塔和拉普拉斯金字塔
下采样:cv2.pyrDown(src, dstsize=[nrow, ncol])
上采样:cv2.pyrUp(src,dstsize=[ncol, nrow])
要注意的是上采样中的dstsize中的尺寸顺序与常规顺序是反着的,顺序为 高,宽
import os
import cv2
import matplotlib.pyplot as plt
import numpy as np
import time
def pyrGuassian(image):
# 高斯金字塔
level = 3
downImages = []
temp = image.copy()
downImages.append(image)
for i in range(level):
img = cv2.pyrDown(temp)
downImages.append(img)
temp = img.copy()
# cv2.imshow("pyr"+str(i), img)
return downImages
def pyrLplance(imageList):
level = len(imageList)
for i in range(level-1, 0, -1):
image = imageList[i]
h, w = imageList[i-1].shape[:2]
# v2.pyrUp的参数dstsize和ndarray.shape(取前两位)是反序的,即 不能直接 dstsize=imageList[i-1].shape[:2]
Ru = cv2.pyrUp(image, dstsize=[w, h])
imageExp = cv2.subtract(imageList[i-1], Ru)
cv2.imshow("imageExp_"+str(i), imageExp)
filePath1 = r'G:\NNdataSet\coco128\images\train2017\000000000030.jpg'
src = cv2.imread(filePath1)
pyrLplance(pyrGuassian(src))
cv2.waitKey(0)
cv2.destroyAllWindows()