参考资料
视频
这些博客就是搭配上面那个视频使用的
这篇也是这个视频的,这个比较齐
参考1
实例参考
cv2.namedWindow
import cv2
import numpy as np
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 600, 800) # 自己设定窗口图片的大小
img=cv2.imread("./pic/bank.png",0)#0表示灰度图方式读取图片 1表示以RGB方式读取 -1直接读取原图不做任何改变
cv2.imshow('img', img)#显示在img这个窗体中
img=cv2.imread("./pic/bank.png",1)#0表示灰度图方式读取图片 1表示以RGB方式读取,忽略alpha通道(默认) -1直接读取原图不做任何改变
cv2.imshow('RGB', img)
img=cv2.imread("./pic/bank.png",-1)#0表示灰度图方式读取图片 1表示以RGB方式读取 -1直接读取原图不做任何改变
cv2.imshow('original drawing', img)
cv2.waitKey(0)
用微信截图功能就能看到bank的大小就是600×800
cv2.imread
注意读取的图片不能是中文的 不然会报错
cv2.imread(filepath,flags)
1、参数说明:
- filepath:要读入图片的完整路径
- flags:读入图片的标志
2、flag
- cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道 1
- cv2.IMREAD_GRAYSCALE:读入灰度图片 0
- cv2.IMREAD_UNCHANGED:顾名思义,读入完整图片,包括alpha通道 ** **
alpha通道是一个8位的灰度通道,该通道用256级灰度来记录图像中的透明度复信息,定义透明、不透明和半透明区域,其中黑表示全透明,白表示不透明,灰表示半透明。
import cv2
import numpy as np
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 600, 800) # 自己设定窗口图片的大小
img=cv2.imread("./pic/bank.png",0)#0表示灰度图方式读取图片 1表示以RGB方式读取 -1直接读取原图不做任何改变
cv2.imshow('img', img)#显示在img这个窗体中
img=cv2.imread("./pic/bank.png",1)#0表示灰度图方式读取图片 1表示以RGB方式读取,忽略alpha通道(默认) -1直接读取原图不做任何改变
cv2.imshow('RGB', img)
img=cv2.imread("./pic/bank.png",-1)#0表示灰度图方式读取图片 1表示以RGB方式读取 -1直接读取原图不做任何改变
cv2.imshow('original drawing', img)
cv2.waitKey(0)
用微信截图功能就能看到bank的大小就是600×800
cv2.cvtColor
颜色转换
cv2.cvtColor(input_image, flag)
- input_image:需要转换的图片
- flag:转换类型,灰度cv2.COLOR_BGR2GRAY
- 返回值:转换后的图片
cv2.imshow()
cv2.imShow()函数可以在窗口中显示图像。该窗口和图像的原始大小自适应(自动调整到原始尺寸)。
- 第一个参数是一个窗口名称(也就是我们对话框的名称),它是一个字符串类型。
- 第二个参数是我们的图像。
- 您可以创建任意数量的窗口,但必须使用不同的窗口名称。
cv2.waitKey(0)
- 是一个和键盘绑定的函数,它的作用是等待一个键盘的输入(因为我们创建的图片窗口如果没有这个函数的话会闪一下就消失了,所以如果需要让它持久输出,我们可以使用该函数)。
- 它的参数是毫秒级。该函数等待任何键盘事件的指定毫秒。如果您在此期间按下任何键,程序将继续进行。我们也可以将其设置为一个特定的键。
- 设置 waitKey(0) , 则表示程序会无限制的等待用户的按键事件(任意按键)
cv2.destroyALLWindows()
- 销毁我们创建的所有窗口。
- 如果要销毁特定窗口,使用函数cv2.destroyWindow(),其中传递确切的窗口名称作为参数。(应该是使用创建窗口时所使用的窗口名称,字符串类型。)
创建一个窗口,图片显示在其中
先创建一个窗口,之后在需要的时候将图像加载到该窗口。
def imshowing (img):
cv2.namedWindow('img', cv2.WINDOW_NORMAL)#cv2.WINDOW_Normal,则可以调整窗口的大小。
cv2.resizeWindow('img', 600,800) # 自己设定窗口的大小 图片在其中显示 不会改变其像素个数
cv2.imshow('img', img)
print(img.shape)#元素个数
cv2.waitKey(0)
cv2.namedWindow()函数可以指定窗口是否可以调整大小。
- 在默认情况下,标志为cv2.WINDOW_AUTOSIZE。
- 但是,如果指定标志为cv2.WINDOW_Normal,则可以调整窗口的大小。
cv2.imwrite
详解
函数 cv2.imwrite() 用于将图像保存到指定的文件。
retval = cv2.imwrite(filename, img [, paras])
1、参数
- filename:要保存的文件的路径和名称,包括文件扩展名
- img:要保存的 OpenCV 图像,nparray 多维数组
- paras:不同编码格式的参数,可选项(一般可以不填这项,如果要填的话可以看上面的详解,里面有详解)
cv2.resize
图片缩放
cv2.resize(InputArray src, OutputArray dst, Size, fx, fy, interpolation)
1.输出尺寸格式为(宽,高)
2.默认的插值方法为:双线性插值
import cv2 as cv
# 读入原图片
img = cv.imread('./pic/bank.png')
# 打印出图片尺寸
print(img.shape)
# 将图片高和宽分别赋值给x,y
x, y = img.shape[0:2]
# 显示原图
cv.imshow('OriginalPicture', img)
# 缩放到原来的二分之一,输出尺寸格式为(宽,高)
img_test1 = cv.resize(img, (int(y / 2), int(x / 2)))
cv.imshow('resize0', img_test1)
# 最近邻插值法缩放
# 缩放到原来的四分之一
img_test2 = cv.resize(img, (0, 0), fx=0.25, fy=0.25, interpolation=cv.INTER_NEAREST)
cv.imshow('resize1', img_test2)
cv.waitKey()
cv.destroyAllWindows()
注:如果要缩小图像,建议选择:cv2.INTER_AREA;如果要放大图像,cv2.INTER_CUBIC效果更好但是速度慢,cv2.INTER_LINEAR效果尚可且速度快。进行缩放时, dsize和fx、fy 二选一即可。
cv2.medianBlur
dst=cv2.medianBlur(src,ksize)
- dst是返回值,表示进行中值滤波后得到的处理结果。
- src 是需要处理的图像,即源图像。它能够有任意数量的通道,并能对各个通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F 或者 CV_64F中的一种。
- ksize 是滤波核的大小。滤波核大小是指在滤波处理过程中其邻域图像的高度和宽度。需要注意,核大小必须是比1大的奇数,比如3、5、7等。
cv2.threshold()
阈值的作用是根据设定的值处理图像的灰度值,比如灰度大于某个数值像素点保留。通过阈值以及有关算法可以实现从图像中抓取特定的图形,比如去除背景等。
th,res=cv2.threshold (src, thresh, maxval, type)
- src:源图片,必须是单通道
- thresh:阈值,取值范围0~255
- maxval:填充色,取值范围0~255
- type:阈值类型,具体见下表
- th:和thresh一样
- res:经处理后的图片
cv2.findContours()轮廓检测
binary, countours, hierarchy=cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
1、binary:寻找轮廓的图像
2、mode:表示轮廓的检索模式,有四种:
- cv2.RETR_EXTERNAL表示只检测外轮廓
- cv2.RETR_LIST检测的轮廓不建立等级关系
- cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
- cv2.RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次。用这个就好了。说白了 这个就是将所有轮廓都存下来了,以后想用哪个就直接调就行了。
3、method:为轮廓的近似(逼近)办法
- cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
- cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。
4、返回值
- cv2.findContours()函数首先返回一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示。(新版已经没有这个返回值了,其实也用不到这个)
- 轮廓本身
- 每条轮廓对应的属性。
5、注意点
- 需要注意的是cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),所以读取的图像要先转成灰度的,再转成二值图
- findcontours函数会“原地”修改输入的图像。这一点可通过下面的语句验证,执行这些语句后会发现原图被修改了。
cv2.imshow("binary", binary)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow("binary2", binary)
- 新版只有两个返回值
import cv2
def imshowing (img):
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 545,408) # 自己设定窗口图片的大小
cv2.imshow('img', img)
cv2.waitKey(0)
img = cv2.imread('../pic/newxiaoyuan.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#灰度
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)#二值
#cv2.RETR_TREE:将所有轮廓都存下来了,以后想用哪个就直接调就行了。
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
draw_img1=img.copy();#注意要用copy 不然draw是会在原图上操作 且会将其保存下来
cv2.drawContours(draw_img1, contours, -1, (0, 0, 255), 3)#最后一个三就是线条的宽度
imshowing(draw_img1)
#算轮廓1的面积 与轮廓的周长
draw_img2=img.copy()
cv2.drawContours(draw_img2, contours,0 , (0, 0, 255), 3)#最后一个三就是线条的宽度
imshowing(draw_img2)
cnt=contours[0]
print(cv2.contourArea(cnt))
print(cv2.arcLength(cnt,True))
cv2.drawContours 轮廓的绘制
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])
- image:指明在哪幅图像上绘制轮廓;
- contours:轮廓本身,在Python中是一个list;
- contourIdx:指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。
- 后面的参数很简单。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。
轮廓面积与周长
cv2.contourArea()、cv2.arcLength()
轮廓面积与周长
//c#
double cnt = Cv2.ContourArea(contours[i]);
#算轮廓1的面积 与轮廓的周长
draw_img2=img.copy()
cv2.drawContours(draw_img2, contours,0 , (0, 0, 255), 3)#最后一个三就是线条的宽度
imshowing(draw_img2)
cnt=contours[0]
print(cv2.contourArea(cnt))
print(cv2.arcLength(cnt,True))
cv2.minMaxLoc()
求矩阵的最小值,最大值,并得到最大值,最小值的索引
import numpy as np
import cv2
a=np.array([[1,2,3,4],[5,67,8,9]])
min_val,max_val,min_indx,max_indx=cv2.minMaxLoc(a)
print(min_val,max_val,min_indx,max_indx)
out:
1.0 67.0 (0, 0) (1, 1)
cv2.boundingRect
使用boundingRect最好参数是二值图,这个方法确定是只能找到一个大框,不能分别画出各自的轮廓
x, y, w, h = cv2.boundingRect(cnt)
- 用一个最小的矩形,把传递进来的东西给包起来。
- cnt是一个轮廓点集合,也就是它的参数,可以通过cv2.findContours获取。或者是一个二值图
- x,y是矩阵左上点的坐标,w,h是矩阵的宽和高
cv2.rectangle
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)画出矩形
- 和cv2.boundingRect配合着使用 一个找出来 一个画出来
- 第一个参数:img是原图
- 第二个参数:(x,y)是矩阵的左上点坐标
- 第三个参数:(x+w,y+h)是矩阵的右下点坐标
- 第四个参数:(0,255,0)是画线对应的rgb颜色
- 第五个参数:2是所画的线的宽度
import cv2
import numpy as np
#导入图片
bgr_img = cv2.imread("./2.jpg")
#再复制一张
img=bgr_img.copy();
#灰度
gray_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2GRAY)
#二值化
th, binary = cv2.threshold(gray_img, 0, 255, cv2.THRESH_OTSU)
cv2.imshow('binary', binary)
cv2.waitKey(0)
#找到轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#在bgr_img中将轮廓画出
cv2.drawContours(bgr_img, contours, -1, (0, 0, 255), 3)
cv2.imshow('bgr_img', bgr_img)
cv2.waitKey(0)
#找出将轮廓包住的最大矩形
bounding_boxes = [cv2.boundingRect(cnt) for cnt in contours]
#将每个轮廓包住的最大矩形画在bgr_img图中(这个图已经有被画好轮廓了)
for bbox in bounding_boxes:
[x, y, w, h] = bbox
#这样应该就是一次循环画一个画出每一个
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow("finally", img)
cv2.waitKey(0)
# #直接传入二值图,能找到一个大框,但不能画出各自的轮廓
# x,y,w,h =cv2.boundingRect(binary)
# cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
# cv2.imshow("finally", img)
# cv2.waitKey(0)
Mat.ptr
cv::Mat image = cv::Mat(400, 600, CV_8UC1); //宽400,长600
uchar * data00 = image.ptr<uchar>(0);
uchar * data10 = image.ptr<uchar>(1);
uchar * data01 = image.ptr<uchar>(0)[1];
解释:
- 定义了一个Mat变量image。
- data00是指向image第一行第一个元素的指针。
- data10是指向image第二行第一个元素的指针。
- data01是指向image第一行第二个元素的指针。
注意:
- image.ptr(1);指的不是image中第二个像素,而是第一行第二个像素的指针。
- 使用上面的代码举例:image有400行,有400*600个像素。假设现在你想得到第3行第42个像素的指针
uchar * data = image.ptr<uchar>(3)[41];
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat src, gray,gray_clone;
src = imread("../../lena.jpg");
imshow("原图", src);
cvtColor(src, gray, CV_BGR2GRAY);
//复制一份灰度图
gray_clone = gray.clone();
imshow("灰度图", gray);
//原图画线
for(int i = 0;i<src.rows;i++)
for (int j = 0; j < src.cols; j++) {
uchar* p = src.ptr<uchar>(i, j);//具体某一个像素的指针
//原图是彩色图,操作三个通道修改颜色
if (i == j) {
p[0] = 0;
p[1] = 255;
p[2] = 255;
}
}
imshow("原图画线", src);
//灰度图画线方法1
double t1 = getTickCount();
for (int i = 0; i < gray.rows; i++)
for (int j = 0; j < gray.cols; j++) {
uchar* p = gray.ptr<uchar>(i, j);
//灰度图是单通道的,只需要操作一个通道即可
if (i == j) {
p[0] = 255;
}
}
double time_consume_1 = (getTickCount() - t1) / getTickFrequency();
printf("灰度图画线方法1耗时:%.3f\n", time_consume_1);
imshow("灰度图画线1", gray);
//灰度图画线方法2
double t2 = getTickCount();
for (int i = 0; i < gray_clone.rows; i++) {
uchar* p = gray_clone.ptr<uchar>(i);//这样写就是某一行
for (int j = 0; j < gray_clone.cols; j++) {
if (i == j)
p[j] = 255;//某一行的第j个
}
}
double time_consume_2 = (getTickCount() - t2) / getTickFrequency();
printf("灰度图画线方法2耗时:%.3f\n", time_consume_2);
imshow("灰度图画线2", gray_clone);
waitKey(0);
return 0;
}
cv2.getStructuringElement
详解
在使用opencv的过程中,我们经常需要各种各样的卷积核。如果是正方形的核还好说,但是有时候需要定义椭圆形或者十字形的核,我们就需要用到cv2.getStructuringElement()函数了
1、第一个参数表示核的形状。可以选择三种
- 矩形:MORPH_RECT;
- 交叉形:MORPH_CROSS;
- 椭圆形:MORPH_ELLIPSE;
2、第二个参数表示核的尺寸。