opencv如何批量读取文件夹中图片

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opencv如何批量读取文件夹中图片相关的知识,希望对你有一定的参考价值。

参考技术A Opencv读取文件夹连续图片,RGB分量显示,图像灰度化
1.读取文件夹连续图片
刚开始学习图像处理,开始只能一次读入一张图片,今天从网上查了一些资料,自己写了一个可以连续读取多张图片函数。
char filename[100];
char windowname[100];
IplImage* pScr;
unsigned char *Readfigsmethod1(int num)// 读入num个图片

for(int i=1;i<=num;i++)

sprintf(filename,"D:/test/%d.jpg",i);// 将图片以数字命名:例如1.jpg 2.jpg等,放入D:/test/文件夹下
sprintf(windowname,"window%d.jpg",i);
pScr=cvLoadImage(filename,1);//导入图片
cvNamedWindow(windowname,CV_WINDOW_AUTOSIZE);
cvShowImage(windowname,pScr);//显示图片
//cvWaitKey(0);


cvWaitKey(0);
cvReleaseImage(&pScr);//释放图片
cvDestroyAllWindows();//销毁窗口

return 0;


注释:连续读取图片主要问题在于filename指向图片目录, sprintf(filename,"D:/test/%d.jpg",i)的使用可以使得filename可以从1.jpg,2.jpg,一直到num.jpg. filename=D:/test/i.jpg.
2.RGB分量显示,图像灰度化
// RGBSPLIT.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
//#include "afx.h"
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char filename[100];
char filename1[100];
char windowname[100];
IplImage* pScr;
IplImage *img1;
IplImage *img=0;
IplImage *img_red=0;
IplImage *img_green=0;
IplImage *img_blue=0;
unsigned char *Readfigsmethod1(int num);//实现连续读取图片的函数
unsigned char *RGBsplit(IplImage *img);//实现RGB量分开显示的函数
unsigned char *RGBtoGray(IplImage *img);//实现灰度化函数
int main(int argc, char *argv[])


img=cvLoadImage("D:\\test\\1.jpg");
cvNamedWindow("lena",CV_WINDOW_AUTOSIZE);//创建窗口,窗口名字lena
cvShowImage("lena",img);//载入转化后的图像
RGBsplit(img);//调用RGB分开显示函数,若想实现其他功能,在此处调用其他函数即可。但是显示后cvReleaseImage()中相应参数要更改成显示的对象。
cvWaitKey(0);
cvReleaseImage(&img);
cvReleaseImage(&img_red);
cvDestroyAllWindows();

return 0;

unsigned char *Readfigsmethod1(int num)

for(int i=1;i<=num;i++)

sprintf(filename,"D:/test/%d.jpg",i);
sprintf(windowname,"window%d.jpg",i);
pScr=cvLoadImage(filename,1);
cvNamedWindow(windowname,CV_WINDOW_AUTOSIZE);
cvShowImage(windowname,pScr);
//cvWaitKey(0);


cvWaitKey(0);
cvReleaseImage(&pScr);
cvDestroyAllWindows();

return 0;

unsigned char *RGBtoGray(IplImage *img)


img1 = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
//色彩空间转换,将源彩色图像img转化成目标灰色图像imag1
cvCvtColor(img,img1,CV_BGR2GRAY); //关键
cvNamedWindow("GrayImage",CV_WINDOW_AUTOSIZE);//创建窗口,窗口名字GrayImage
cvShowImage("GrayImage",img1);//载入转化后的图像

return 0;

unsigned char *RGBsplit(IplImage *img)

//IplImage* imgeR,img_blue,imageG,imgGRAY;
int width=img->width;
int height=img->height;
int channel=img->nChannels;
int widthStep=img->widthStep;
int i,j;

img_red= cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
img_green= cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
img_blue= cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
for (i=0;i<height;i++)


for (j=0;j<width;j++)

CvScalar t=cvGet2D(img,i,j);
double s0=t.val[0];
double s1=t.val[1];
double s2=t.val[2];
CvScalar m_blue=cvScalar(s0,0,0,0);
CvScalar m_green=cvScalar(0,s1,0,0);
CvScalar m_red=cvScalar(0,0,s2,0);
cvSet2D(img_blue,i,j,m_blue);
cvSet2D(img_green,i,j,m_green);
cvSet2D(img_red,i,j,m_red);


cvNamedWindow("imgred",1);
cvShowImage("imgred",img_red);
return 0;
本回答被提问者和网友采纳

详解C++标准库<sstream>中的类stringstream,并利用它实现OpenCV下的图片批量读取

本文详解C++标准库中的类stringstream,并利用它实现OpenCV下的批量图片读取。

目录

一、字符串格式化函数sprintf()存在的问题

在进行图像处理时,我们常常需要批量读取图片,本文就说下如何利用C++标准库中的类stringstream实现OpenCV下的批量图片读取。

当然本文要批量读取的图片在名字上是有数值规律的。

比如下面这些图片:

上面这些图片的名字是有数值规律的,其最后的数字从1依次递增到11。
所以在读取这些图片时我们可以依据其数值规律批量生成这些图片的名字,然后用这些批量生成的名字即可进行图片的批量读取。

这其中的关键便是如何把数值批量转化成字符串?

​当然,您可以选择C标准库<stdio.h>中的字符串格式化函数sprintf()来解决这个问题。在我的博文https://blog.csdn.net/wenhao_ir/article/details/51538445 的代码中也用到了函数sprintf()。

但是函数sprintf()存在一些问题:
①假设你想使用sprintf()函数将一个变量从int类型转换到字符串类型。为了正确地完成这个任务,你必须确保证目标缓冲区有足够大空间以容纳转换完的字符串。假设你要得到的字符串字节数范围为1~100,那你必须保证你为sprintf()函数定义的目标缓冲区有100字节的大小。比如下面这个例子。

int x;
int y;
char temp[16];
sprintf(temp, "(%d,%d)", x, y);

上面的代码是没有问题的,但是下面的代码就有问题了:

int x;
int y;
char temp[16];
sprintf(temp, "My current coordinate value is (%d,%d)", x, y);

为什么有问题,因为字符串"My current coordinate value is (%d,%d)"是33个字节,超过了字符数组temp的长度16,所以程序运行时就会报错了。
从这个例子我们就会想,如果sprintf()函数在转换时能根据任务需要自动分配存储空间那不是更好吗?

②使用sprintf()函数时必须使用正确的格式化符。如果使用了不正确的格式化符,会导致非预知的后果,比如下面这个例子。

int n=10000;
chars[10];
sprintf(s,%d”,n);// s中的内容为“10000”

上面这个代码目前是没有问题的,但是对上面代码的一个微小的改变就会使程序崩溃。

int n=10000;
char s[10];
sprintf(s,%f”,n);// 错误的格式化符

在上面的代码中,错误地使用了%f格式化符来替代了%d。
从这个例子我们就会想,sprintf()函数在转换时要是能自动推导出正确的类型,那不是更好吗?

二、详细介绍C++标准库中的类stringstream

C++标准库中的就解决了上面这些问题。C++标准库中的提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性、类型安全和可扩展性。
库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。

我们常用的是类stringstream,毕竟每个转换都要涉及到输入和输出操作,所以我的这篇博文重点介绍类stringstream的使用。

类stringstream的使用其实很简单,一个简单的示例代码如下:

//该代码实现整型数据转化为字符串
#include <sstream>
#include <iostream>

using namespace std;

int main()

	int n = 12345;
	stringstream ss;
	string str;
	ss << n;
	ss >> str;

	cout <<str<< endl<< endl;

上面的代码运行结果如下:

注意:经过上面代码的处理,输出的12345并不是整型数值12345,而是字符串12345。

以类stringstream为例,之所以能解决上面函数sprintf()遇到的两个问题:
一是因为当流传入和传出stringstream对象时(比如上面代码中的“ss << n”和“ss >> str”),它能自动识别推导格式,而不用用户再去手动设置。
二是因为使用string对象来代替字符数组(对应上面的代码“string str;”),这样可以避免流输出时缓冲区溢出的危险(对应上面的代码 “ss >> str”)。

正是因为类stringstream能自动识别推导格式,所以使得它不仅能实现数值类型转化为字符串,也能实现其它类型间的相互转换。
上面的代码实现了整型转换为字符串,我们还可以利用它实现字符串转换为浮点型,比如下面的代码。

//该代码实现字符串型数据转化为浮点型数据
#include <sstream>
#include <iostream>

using namespace std;

int main()

	string my_string="10000";
	float f_1=0;
	stringstream ss;
	string str;
	ss << my_string;
	ss >> f_1;

	cout <<f_1<< endl<< endl;


代码运行结果如下:

当然,整型转浮点型也是可以的,比如下面的代码:

//该代码实现整型数据转化为浮点型数据
#include <sstream>
#include <iostream>

using namespace std;

int main()

	int n = 1000;
	float f_1=0;
	stringstream ss;
	string str;
	ss << n;
	ss >> f_1;

	cout <<f_1<< endl<< endl;


运行结果如下:

要提醒的是:
stringstream对象的构造和析构函数是比较耗费CPU时间的,所以我们如果要多次进行转换,尽量重复使用同一个stringstream对象。但是在多次转换中使用同一个stringstream对象,要记住再每次转换前要使用clear()方法,否则得不到正确的正果。比如下面的例子:

#include <sstream>
#include <iostream>

using namespace std;

int main()

	int n = 1000;
	float f_1=0;
	stringstream ss;
	string str;
	ss << n;
	ss >> f_1;
	cout <<f_1<< endl<< endl;

	//再次使用对象ss进行转换
	string my_string="99999";
	float f_2=0;
	ss << my_string;
	ss >> f_2;
	cout <<f_2<< endl<< endl;


上面代码的运行结果如下:

按理,f_2中的值应该是“99999”才对,但从上面的运行结果中我们看到f_2中的值为0,这就是错误的结果。解决方法是在第二次使用stringstream对象前先用方法clear()。下面的代码便能得到正确的结果:

#include <sstream>
#include <iostream>

using namespace std;

int main()

	int n = 1000;
	float f_1=0;
	stringstream ss;
	string str;
	ss << n;
	ss >> f_1;

	cout <<f_1<< endl<< endl;

	//再次使用对象ss进行转换
	ss.clear(); //再次转换前先clear才能得到正确的结果
	string my_string="99999";
	float f_2=0;
	ss << my_string;
	ss >> f_2;
	cout <<f_2<< endl<< endl;


上面的代码的运行结果如下:

三、利用C++标准库中的类stringstream实现OpenCV下的图片批量读取

如果您认真阅读了本文上面的内容,那么就很容易实现“利用C++标准库中的类stringstream实现OpenCV下的图片批量读取”的程序了。
我们要读取以下图片:

代码如下:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>

using namespace cv;
using namespace std;

#define  NUM  13    //读取image的个数  
int main()

	Mat image;
	string ImgName;
	int n = 1;
	while (n <= NUM)   //13
	
		ImgName = "flower-";
		//int 转换string  
		stringstream ss;
		string str;
		ss << n;
		ss >> str;

		ImgName = ImgName + str;
		ImgName = "F:/material/images/flower-01/" + ImgName + ".jpg";
		cout << "读取:" << ImgName << endl;
		image = imread(ImgName);//读取图片  
		if (image.data == 0)
		
			printf("图片读取失败\\n\\n");
		
		else
		
			printf("图片读取成功\\n\\n");
		
		n++;
	

	waitKey(0);
	system("pause");
	return 0;

上面的代码很简明,没什么好多说的。
代码运行结果如下:

由于咱们的文件夹中不存在“flower-11.jpg”和“flower-12.jpg”,所以程序提示读取失败。
还需要说明的是:在OpenCV的<core.hpp>已经把包含进来了,所以不需再单独include了。

本文就先写到这里,博主水平有限,欢迎在本文下回复指正。
感谢大家的阅读。

以上是关于opencv如何批量读取文件夹中图片的主要内容,如果未能解决你的问题,请参考以下文章

详解C++标准库<sstream>中的类stringstream,并利用它实现OpenCV下的图片批量读取

OpenCV-Python实战 —— OpenCV 实现批量将 bmppngjpg格式图片转换为 png 格式图片

如何批量读取bmp图片的原始高和宽

从文件夹中读取图像(OpenCV)

Opencv读取图片像素值并保存为txt文件

opencv读取ENVI标准格式