OpenCV 图片的读取、(并排)显示与保存

发布时间 2023-11-07 16:21:52作者: 一杯清酒邀明月

前言

  C++和python两者的使用语法都是相同的

一、读取(imread和imdecode)

1、imread

  由两个参数决定:
  imread(“图片的地址+名称”, 何种形式读取图片)

1 image = cv2.imread("C:/Opencv/lena.jpg", cv2.IMREAD_GRAYSCA)  // python
2 cv::Mat image = cv::imread("C:/Opencv/lena.jpg", 0); // c++

第二个参数,可以使用标志参数,也可以使用简记数字。常用的就是

     读取形式                            标志参数               简记数字
以原图读取(针对有Alpha通道的图片)      IMREAD_UNCHANGED           -1
以单通道的灰度图像读取                  IMREAD_GRAYSCA            0
以3通道BGR的彩色图片读取                 IMREAD_COLOR             1     

2、imdecode
  imread是从文件(磁盘)中直接读取图像数据,imdecode是从内存缓冲区中读取数据,并解码成图像格式。

  使用imdecode的优点在于可以从内存中直接解码图像数据,而不需要将数据保存到磁盘再进行读取。在某些场景中是有用的,如网络传输的数据源,摄像头捕获的图像数据。

  imdecode与image的使用有一点要注意:imread是传入图片路径,转为图片格式;imdecode传入的内存数据(数组形式),转为图片格式。就以上面的简单例子:从文件中读取图片。imdecode的python写法可以为下:

1 # 使用 NumPy 的 fromfile 函数从指定路径中读取图像数据,并将其存储为 NumPy 数组,作为参数传给imdecode解码成图像格式
2 image = cv2.imdecode(np.fromfile("C:/Opencv/lena.jpg", dtype = np.uint8), 1)    # 1为标志参数,3通道读取

  注:一般情况下,读取图像的像素数目小于2^30,这个要求在绝大多数图像处理领域都是不受影响的,但是对于超高分辨率图像的像素数目可能会超过这个阈值,可以通过修改系统变量中的OPENCV_IO_MAX_IMAGE_PIXELS参数调整能够读取的最大像素数目。

二、显示(imshow)
  显示图片一般调试时使用,没有什么特别注意的(反正最终结果也要将其注释掉)。
  常用三件套:1)显示图片窗口 2)窗口的持续时间或阻塞 3)销毁窗口

1 cv::imshow("Show", image); // "Show"是显示窗口的名称,image是读取的图片
2 //cv::waitKey(300) // 窗口持续300ms后关闭,继续后续程序
3 cv::waitKey(0);   // 0 将会一直阻塞程序的执行,直到用户按下键盘上的任意键
4 cv::destroyAllWindows();  // 关闭程序中所有的窗口,一般用于程序的最后

注:如果原图分辨率太大,显示不完全怎么办? 使用namedWindow()这个窗口函数设置一下。

此外,某些场景下想让图片并排表示,来更好的对比效果,可以使用以下方式(仅当展示图片的尺寸相同时):

 1     cv::Mat img = cv::imread("C:/Users/20231.jpg");
 2     cv::Mat img1 = cv::imread("C:/Users/3-353S02073-0_WA.jpg");
 3     cv::Mat img2 = cv::imread("C:/Users/301-4-353S02073-0_WA.jpg");
 4 
 5     // 获取每张图像的大小
 6     int h = img.rows;
 7     int w = img.cols;
 8     int h1 = img1.rows;
 9     int w1 = img1.cols;
10     int h2 = img2.rows;
11     int w2 = img2.cols;
12 
13     // 创建一个大画布用于展示三张图像
14     cv::Mat canvas(std::max(h, std::max(h1, h2)), w + w1 + w2, CV_8UC3, cv::Scalar(0, 0, 0));
15 
16     // 将三张图像放置在合适的位置上
17     img.copyTo(canvas(cv::Rect(0, 0, w, h)));
18     img1.copyTo(canvas(cv::Rect(w, 0, w1, h1)));
19     img2.copyTo(canvas(cv::Rect(w + w1, 0, w2, h2)));
20 
21     cv::imshow("Merged Images", canvas);
22     cv::waitKey(0);
23     cv::destroyAllWindows();

python代码如下:

 1 img = cv2.imread("img.jpg")
 2 img1 = cv2.imread("img1.jpg")
 3 img2 = cv2.imread("img2.jpg")
 4 
 5 # 获取每张图像的大小
 6 h, w, _ = img.shape
 7 h1, w1, _ = img1.shape
 8 h2, w2, _ = img2.shape
 9 
10 # 创建一个大画布用于展示三张图像
11 canvas = np.zeros((max(h, h1, h2), w + w1 + w2, 3), dtype=np.uint8)
12 
13 # 将三张图像放置在合适的位置上
14 canvas[:h, :w] = img
15 canvas[:h1, w:w+w1] = img1
16 canvas[:h2, w+w1:] = img2
17 
18 # 显示合并后的图像
19 cv2.imshow("Merged Images", canvas)
20 cv2.waitKey(0)
21 cv2.destroyAllWindows()

三、保存(imwrite和imencode)

1、imwrite

与读取imread相似,要给出具体保存的路径(地址+图片名)

1     cv::Mat image = cv::imread("C:/Opencv/lena.jpg", cv::IMREAD_GRAYSCALE);
2     cv::imwrite("C:/Opencv/temp/lena.jpg", image);

  值得注意的是批量图片的保存。通常方法都是 :(固定的文件夹地址)+(流动的图片名)

  ( 注:imwrite函数还有第三个参数,用于保存不同格式的图像。如果保存的图像是单通道或三通道,那第三个参数可以忽略。但如果保存的是特殊格式(如16位深度图像),则需要设置第三个参数。)

2、imencode
  imencode函数是将图像数据编码成流数据(如png格式,jpg格式),返回的是一个元组(bool,NumPy),第一个元素是布尔值,表示编码是否成功;第二个是编码后的数据——NumPy数组。若想把数据保存到文件中,还需要其他步骤,例如,python中使用.tofile(.tofile() 是 NumPy 数组的一个方法,用于将数组中的数据以二进制形式写入文件):

1 image = cv2.imdecode(np.fromfile("C:/Opencv/lena.jpg", dtype = np.uint8), -1)
2 cv2.imencode('.png', image)[1].tofile("C:/Opencv/temp/ena.png") // 索引[1]取出元组中的第二个元素,即编码后的图像数据

总结

  imdecode和imencode是进行与内存缓冲区之间的操作(而不是磁盘),在某些场景下更加高效,但C++中使用这两个比较繁琐,python中使用较为方便。