想要對大量圖像進(jìn)行簡單處理,我們可以利用代碼實(shí)現(xiàn)。
OpenCV作為開源的圖像處理庫,安裝方便,容易上手,功能強(qiáng)大,受到了很多人的喜愛。
1.背景
-
筆者正在參加全國大學(xué)生智能汽車競賽。由于放假在家,家中沒有鋪設(shè)賽道的條件,我找到了一款上位機(jī),可以將智能車的圖像導(dǎo)入到上位機(jī)中,上位機(jī)提供了在線調(diào)車功能,可以進(jìn)行各種圖像操作,將智能車的圖像處理代碼進(jìn)行簡單的修改,就可以在上位機(jī)中運(yùn)行。
-
但是這款上位機(jī)對圖片有尺寸和格式的要求:bmp格式圖片,分辨率應(yīng)該是在188*120以下。
-
在校調(diào)車期間,我購買了圖傳,將車輛運(yùn)行時的圖像實(shí)時傳到電腦中,便于分析,所以電腦存有大量車輛運(yùn)行中的圖像。
-
但是傳到電腦上的圖為了便于觀察,都自動進(jìn)行了放大處理,放大了5倍。

-
所以我需要做三件事
-
1.將圖片分辨率縮小5倍
-
2.將jpg格式圖片轉(zhuǎn)為bmp格式圖片
-
3.將上述操作重復(fù)進(jìn)行幾萬次
2.軟件環(huán)境
使用win10+vs2017+OpenCV?4.1.1
vs2017與OpenCV安裝配置過程略,csdn上有很多
(之前使用的是vs2020+OpenCV?4.6.0,出現(xiàn)了很多奇奇怪怪的bug,詢問了一位大佬,修改到了上述版本)
3.代碼
法一:利用glob函數(shù)讀取文件夾內(nèi)的所有圖片
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace cv;
using namespace std;
int main()
{
Mat img_5min; //5倍縮放圖
string InputPath = "D:\\Backup\\桌面\\原圖\\*.jpg";//指定路徑,精確到最后一個文件夾,圖片帶格式,名稱用*
vector<String> InputFiles; //定義一個字符串?dāng)?shù)組作為輸入文件
glob(InputPath, InputFiles);//用glob函數(shù)將輸入路徑與輸入文件聯(lián)系起來
if (InputFiles.size() == 0) //檢驗(yàn)是否有圖片
{
cout << "No image files[jpg]" << endl;
return 0;
}
for (int i = 0; i < InputFiles.size(); i++)//image_file.size()代表文件中總共的圖片個數(shù)
{
Mat img = imread(InputFiles[i]);//讀取圖片
resize(img, img_5min, Size(img.cols / 5, img.rows / 5), 0, 0, INTER_NEAREST);//縮放
string OutputPath = "D:\\Backup\\桌面\\修改圖\\" + to_string(i) + ".bmp";//存儲路徑,文件名,文件格式
imwrite(OutputPath, img_5min);//存儲
imshow("src", img_5min);//顯示一下
waitKey(5);//5ms后正常運(yùn)行下一次
}
waitKey(0);
return 0;
}
這也是我在網(wǎng)上找到的比較多的辦法,利用glob函數(shù)讀取文件夾內(nèi)所有圖片,記錄數(shù)量遍歷。
由于我需要將圖片縮放,在其中加了一句,將讀取到的圖片長寬除以5,另存。
resize(img, img_5min, Size(img.cols / 5, img.rows / 5), 0, 0, INTER_NEAREST);//縮放5倍
效果很好,文件格式,圖片大小都和預(yù)想的一樣,完成了修改。
但是有個問題,看下面的圖,這是我的原圖集。
在修改過的圖集中,順序就改變了,相同的序號圖片內(nèi)容卻不是一樣的。貌似是有規(guī)律的變。
這組圖對我來說就無法使用了,因?yàn)橐氲氖莻€動態(tài)過程,圖片的順序是有要求的。
于是我就觀察了原始代碼。
這套代碼的核心就是讀取目錄中的圖片,讀取圖片數(shù)量,然后遍歷所有圖,讀一個,改一個,存一個,然后判斷圖像有沒有訪問完。
那么如果我知道圖片數(shù)量,圖片命名規(guī)律,我就知道每個圖片的路徑,是不是直接訪問了呢?
答案是可以的
法二:修改訪問路徑批量操作圖片
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace cv;
using namespace std;
int main()
{
Mat image; //原圖
Mat image_5_min; //5倍縮放圖
int i = 0;
for (i = 0; i < 1100; i++)
{
string InputPath = "D:\\Backup\\桌面\\原圖\\" + to_string(i) + ".jpg";
image = imread(InputPath, 0);
if (image.data == nullptr)//nullptr是c++11新出現(xiàn)的空指針常量
{
cout << "名稱應(yīng)該為" << i << "的圖片文件不存在" << endl;
break;
}
resize(image, image_5_min, Size(image.cols / 5, image.rows / 5), 0, 0, INTER_NEAREST);//五倍縮
string OutputPath = "D:\\Backup\\桌面\\修改圖\\" + to_string(i) + ".bmp";
imwrite(OutputPath, image_5_min);
waitKey(5);
}
waitKey(0);
return 0;
}
在運(yùn)行之后效果很好。
相同的序號圖片內(nèi)容是一樣的。
我的原圖集的命名是連續(xù)的,0.jpg~999.jpg,修改訪問路徑可以很好遍歷,只要命名是連續(xù)的,想要訪問更多圖片也只需要更改程序中for循環(huán)的條件而已,十分的方便。
對于圖片命名是不是連續(xù)的情況,比如我讓我的隊(duì)友找了一下他電腦里的一些跑車時候存下來的圖片,他發(fā)來的文件是這樣的。、

我第一次運(yùn)行時候看著原圖有800多張圖片,用上面的程序跑完一遍只生成了300多張圖片,提示我沒有找到11676.jpg。感覺有點(diǎn)問題,不應(yīng)該呀。我就看了一下文件,的確沒有11676.jpg。
文件名從11675.jpg跳躍到了12846.jpg,顯然我的隊(duì)友只將一些片段截取了出來,他發(fā)給我的文件夾內(nèi)有3段,文件名跳躍了2次,我又懶得找到每個跳躍的地方,記錄跳躍起始點(diǎn),結(jié)束點(diǎn)。
于是我靈機(jī)一動,選中第一張圖片,再ctrl+a全選圖片,將第一張圖片重命名為01,按下enter。
結(jié)果如下,833個項(xiàng)目按照Windows的系統(tǒng)命名規(guī)則進(jìn)行了重命名了。
理論上無論多少圖片,系統(tǒng)都會從01順下去命名,這樣我只需要將代碼略加修改,就可以一次性修改所有的圖片。
我只需要將代碼中的路徑按照上面的命名規(guī)則:01(i).jpg?進(jìn)行改變路徑即可,代碼如下
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace cv;
using namespace std;
int main()
{
Mat image; //原圖
Mat image_5_min; //5倍縮放圖
int i = 1;
for (i = 1; i < 1100; i++)
{
string InputPath = "D:\\Backup\\桌面\\左環(huán)島圖片\\左環(huán)島圖片\\01 (" + to_string(i) + ").jpg";
image = imread(InputPath, 0);
if (image.data == nullptr)//nullptr是c++11新出現(xiàn)的空指針常量
{
cout << "名稱應(yīng)該為" << i << "的圖片文件不存在" << endl;
break;
}
resize(image, image_5_min, Size(image.cols / 5, image.rows / 3.5), 0, 0, INTER_NEAREST);//隊(duì)友和我的圖像不一樣,縮放比例可以調(diào)整
string OutputPath = "D:\\Backup\\桌面\\修改圖\\" + to_string(i) + ".bmp";
imwrite(OutputPath, image_5_min);
waitKey(5);
}
waitKey(0);
return 0;
}
對比上面,改變其實(shí)只有一點(diǎn),根據(jù)我文件夾的位置、命名規(guī)則,我改變了輸入文件路徑,讓他變成了一個動態(tài)的輸入路徑。
string InputPath = "D:\\Backup\\桌面\\左環(huán)島圖片\\左環(huán)島圖片\\01 (" + to_string(i) + ").jpg";
這樣就可以非常優(yōu)雅的批量修改圖片。
4.總結(jié)
對于圖像批量修改我們可以使用glob函數(shù)讀取文件夾內(nèi)所有圖片,記錄數(shù)量遍歷。但是可能會造成文件亂序,對于順序要求不高的可以使用。
也可以根據(jù)命名順序,修改訪問路徑,進(jìn)行批量修改。優(yōu)點(diǎn)是不會亂序,但是需要文件名有規(guī)律。
最終也是實(shí)現(xiàn)了上位機(jī)讀取圖片,代碼對圖片進(jìn)行分析,進(jìn)行相關(guān)操作,從而仿真調(diào)車
5.一些猜想和注意事項(xiàng)
5.1猜想
glob函數(shù)有可能根據(jù)文件大小,根據(jù)地址訪問。原圖中大小不一樣,有可能造成訪問某張個圖片時發(fā)生了錯誤,序號標(biāo)錯了。

5.2注意事項(xiàng)
1.在vs2017運(yùn)行,很容易出現(xiàn)正在加載符號,程序就會等著符號加載完在運(yùn)行,很煩人,我也找了很多解決辦法,效果不好,意外的發(fā)現(xiàn)有個很簡單的好辦法。
不要點(diǎn)擊vs中間的本地Windows調(diào)試器,要使用ctrl+f5,就可以避免亂七八糟的符號加載。
原理貌似是按下本地Windows調(diào)試器是進(jìn)行程序的調(diào)試,需要一些組件之類的東西支持,而ctrl+f5是運(yùn)行而不調(diào)試,可以省略很多東西的加載。
2.文件夾路徑都是雙杠\\,因?yàn)閱胃軙徽J(rèn)為轉(zhuǎn)義符,雙杠才是\
希望對你有所幫助。
本人菜雞一只,各位大佬發(fā)現(xiàn)問題歡迎留言指出。文章來源:http://www.zghlxwxcb.cn/news/detail-439089.html
qq:2296449414文章來源地址http://www.zghlxwxcb.cn/news/detail-439089.html
到了這里,關(guān)于C++中利用OpenCV進(jìn)行圖像批量處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!