我门要对某个目录下所有图像文件进行统一处理,如果图像的数量过多,那么手动地一张张处理就会显得有些麻烦。本文使用OpenCV和bash来完成我们指定的任务。
任务
将目录A下的所有统一格式的jpg图像变成统一尺寸的图像,输出到目录B中。A目录下图像的宽度和高度需要去掉最后一列、最后一行,并且使得输出图像的高度小于宽度。
技术
OpenCV读取图像;访问图像中的元素;OpenCV写图像到磁盘。
BASH扫描每个输入图像;确定输出图像名称。
OpenCV对图像进行处理
源代码如下:
#include <cassert>#include <iostream>#include <vector>#include <string>#include <algorithm>#include "cv.hpp"#include "opencv2/opencv.hpp"//#include "opencv2/core.hpp"#include "opencv2/highgui/highgui_c.h"using namespace std;using namespace cv;int main(int argc, char **argv){if (3 != argc){cerr << "input error\n";cerr << "Usage : " << argv[0] << " <input image> <output directory>" << endl;return -1;}// reading the input imageMat oim = imread(argv[1]);if (oim.empty())return -1;const int rows = oim.rows;const int cols = oim.cols;Mat fim(rows-1, cols-1, CV_8UC3);for (int r = 0; r < (rows-1); r++){for (int c = 0; c < (cols-1); c++){fim.at<Vec3b>(r,c) = oim.at<Vec3b>(r,c);}}// rotate 90'Mat lim;if (rows > cols){lim.create(cols-1, rows-1, CV_8UC3);for (int r = 0; r < (cols-1); r++){for (int c = 0; c < (rows-1); c++){lim.at<Vec3b>(r,c) = fim.at<Vec3b>(c,cols-2-r);}}}else{lim = fim;}// savingstring filename(argv[1]);int dirpos = filename.find_last_of('/');if (string::npos == dirpos){dirpos = 0;}else{dirpos += 1;}string wfn = &filename[dirpos];string outdir = string(argv[2]);string outfile = outdir+string("/")+wfn;vector<int> compression_params;compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);compression_params.push_back(100);imwrite(outfile, lim, compression_params);if(lim.cols != 480 || lim.rows != 320)cerr << "size error" << endl;return 0;}
程序分三大步骤完成:读如程序选项中的输入图像;对输入图像去除最后一行和最后一列,判断高度和宽度的要求(是否进行反转90度);将图像写入磁盘。
写入磁盘时,使用了jpeg压缩方式,压缩的参数设置为100,表示无失真压缩。
输入图像的名称和输出图像的名称使用同一个。
bash处理
用bash对某个目录下的所有图像都处理一次,并且输出到指定的目录。源代码如下:
SPS="input/"DFS=`ls -A ${SPS}*.jpg`JPGDIR="../output/jpg"mkdir -p ${JPGDIR} for fn in $DFSdo echo $fn ./rmRowACols.exe $fn $JPGDIRdone
总结
BASH+C/C++ 合作来完成一个完整的任务,各取所长,兼顾性能和开发难度,目前被我认为是比较简单的方式。
这样作还有一个好处:C\C++语言可以做更多细节,别调用别人的程序要随意一点。