歡迎技術交流和幫助,提供IT相關服務,索要源碼請聯繫博主QQ: 21497936,若該文爲原創文章,未經允許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100735114
目錄
OpenCV開發專欄
持續補充中…
OpenCV開發筆記(四):圖片和視頻數據的讀取與存儲
前言
OpenCV對圖像進行操作,圖像包含圖片和視頻。
OpenCV讀取圖片文件
讀取圖像文件,使用的imread()。
imread()函數返回的是Mat對象,如果讀取函數文件失敗,會返回一個空矩陣(常量cv::Mat::data變量的值是NULL)。
Mat imread(const string& filename, int flags=1 )
- filename:是被讀取或者保存的圖像文件名;
- flag:參數值有三種情況:
flag>0,該函數返回3通道圖像,如果磁盤上的圖像文件是單通道的灰度圖像,則會被強制轉爲3通道;
flag=0,該函數返回單通道圖像,如果磁盤的圖像文件是多通道圖像,則會被強制轉爲單通道;
flag<0,則函數不對圖像進行通道轉換。
imread()函數支持多種文件格式,且該函數是根據圖像文件的內容來確定文
件格式,而不是根據文件的擴展名來確定。
支持的圖像格式:bmp、dib、jpg、jpeg、jpe、png、pbm、pgm、ppm、sr、ras、tiff、tif、exr、jp2。(需要對應的庫支持,開發使用的庫要編譯時添加進去,然後編譯生成opencv庫)
OpenCV存儲圖片文件
保存圖像文件,使用的imwrite()。
imwrite()函數返回的是bool。
bool imwrite(const string& filename,
InputArray image,
const vector<int>& params=vector<int>())
filename是存成指定的文件名,注意格式是由指定的文件擴展名確定。
PNG-是無損壓縮格式,推薦使用。
BMP-格式是無損格式,但是一般不進行壓縮,文件尺寸非常大;
JPEG-格式的文件嬌小,但是JPEG是有損壓縮,會丟失一些信息。
並不是所有的 Mat 對象都可以存爲圖像文件,目前支持的格式只有8U類型的單通道和3通道(顏色順序爲 BGR)矩陣;如果需要要保存16U格式圖像, 只能使用PNG、JPEG 2000和TIFF格式。
如果希望將其他格式的矩陣保存爲圖像文件,可以先用Mat::convertTo()函數或者cvtColor()函數將矩陣轉爲可以保存的格式。
注意:在保存文件時,如果文件已經存在,imwrite()函數不會進行提醒,將直接覆蓋掉以前的文件。
圖片測試Demo
代碼
#if TEST_IMAGE
// 讀取
cv::Mat image = cv::imread("1.jpg");
// 判斷是否讀取成功
if(image.data == NULL)
{
QMessageBox::warning(0, "讀取圖片失敗", "1.jpg");
return;
}
// 顯示
cv::imshow("readImage", image);
// 作一個圖像行列轉換操作,再保存
image = image.t();
// 保存
if(!cv::imwrite("1 to 2.jpg", image))
{
QMessageBox::warning(0, "保存失敗", "1.jpg");
return;
}
#endif
運行效果
OpenCV讀取視頻
圖像文件,可以根據文件擴展名得知圖像的格式。但是此經驗並不能推廣到視頻文件中。有時候會碰到奇怪的問題,都是avi視頻文件,有的能用OpenCV打開,有的不能。
視頻的格式主要由壓縮算法決定,就是視頻編解碼器。視頻文件能讀或者寫,關鍵看是否有相應的編解碼器。
OpenCV 2中提供了兩個類來實現視頻的讀寫。讀視頻的類是VideoCapture,寫視頻的類是VideoWriter。
VideoCapture 既可以從視頻文件讀取圖像,也可以從攝像頭讀取圖像。可以使用該類的構造函數打開視頻文件或者攝像頭。如果 VideoCapture 對象已經創建,也可以使用VideoCapture::open()打開,VideoCapture::open()函數會自動調用VideoCapture::release()函數,先釋放已經打開的視頻,然後再打開新視頻。
OpenCV存儲視頻
使用OpenCV創建視頻與讀視頻不同的是,需要在創建視頻時設置一系列參數,包括:文件名,編解碼器,幀率,寬度和高度等。
編解碼器使用四個字符表示,可以是:
- CV_FOURCC('M','J','P','G')
- CV_FOURCC('X','V','I','D')
- CV_FOURCC('D','I','V','X')
- 還有其他的
如果使用某種編解碼器無法創建視頻文件,請嘗試其他的編解碼器。
將圖像寫入視頻可以使用VideoWriter::write()函數,VideoWriter類中也重載了<<操作符,使用起來非常方便。另外需要注意:待寫入的圖像尺寸必須與創建視頻時指定的尺寸一致。
視頻測試Demo
代碼
#if TEST_VIDEO
cv::VideoCapture videoCapture;
// 打開視頻
if(!videoCapture.open("1.mp4"))
{
QMessageBox::warning(0, "讀取視頻失敗", "1.mp4");
return;
}
int width = 0;
int height = 0;
for(;;)
{
cv::Mat frame;
videoCapture >> frame;
// 第一次進入,記錄視頻尺寸
if(width == 0)
{
width = frame.cols;
height = frame.rows;
}
// 最後一幀之後爲空,退出
if(frame.empty())
{
break;
}
// 顯示
cv::imshow("readVideo", frame);
// 等待1s,有按鍵輸入立即結束本次
if(cv::waitKey(1) >= 0)
break;
}
// 將視頻輸入流返回到第0幀
videoCapture.set(cv::CAP_PROP_POS_FRAMES, 0);
cv::VideoWriter videoWrite;
// 翻轉操作了
width = width + height;
height = width - height;
width = width - height;
if(!videoWrite.open("1 to 1.avi", CV_FOURCC('M','J','P','G'), 25, cv::Size(width, height)))
{
QMessageBox::warning(0, "保存視頻失敗", "1 to 1.avi");
return;
}
QString version = "v1.3.0";
QString text = QString("OpenCVDemo %1 QQ21497936 blog.csdn.net/qq21497936").arg(version);
for(;;)
{
cv::Mat frame;
videoCapture >> frame;
if(frame.empty())
{
break;
}
// 沿對角線行列翻轉
frame = frame.t();
cv::putText(frame,
cv::String(text.toUtf8().data()),
cv::Point(0, height / 2),
cv::FONT_HERSHEY_SCRIPT_SIMPLEX,
0.8,
cv::Scalar(0,0,255),
3,
8,
false);
cv::imshow("readVideo", frame);
videoWrite << frame;
if(cv::waitKey(1) >= 0)
break;
}
#endif
運行效果
然後
Demo源碼
void OpenCVManager::testImageAndVideo()
{
#define TEST_IMAGE (0)
#define TEST_VIDEO (1)
#if TEST_IMAGE
// 讀取
cv::Mat image = cv::imread("1.jpg");
// 判斷是否讀取成功
if(image.data == NULL)
{
QMessageBox::warning(0, "讀取圖片失敗", "1.jpg");
return;
}
// 顯示
cv::imshow("readImage", image);
// 作一個圖像行列轉換操作,再保存
image = image.t();
// 保存
if(!cv::imwrite("1 to 2.jpg", image))
{
QMessageBox::warning(0, "保存失敗", "1.jpg");
return;
}
#endif
#if TEST_VIDEO
cv::VideoCapture videoCapture;
// 打開視頻
if(!videoCapture.open("1.mp4"))
{
QMessageBox::warning(0, "讀取視頻失敗", "1.mp4");
return;
}
int width = 0;
int height = 0;
for(;;)
{
cv::Mat frame;
videoCapture >> frame;
// 第一次進入,記錄視頻尺寸
if(width == 0)
{
width = frame.cols;
height = frame.rows;
}
// 最後一幀之後爲空,退出
if(frame.empty())
{
break;
}
// 顯示
cv::imshow("readVideo", frame);
// 等待1s,有按鍵輸入立即結束本次
if(cv::waitKey(1) >= 0)
break;
}
// 將視頻輸入流返回到第0幀
videoCapture.set(cv::CAP_PROP_POS_FRAMES, 0);
cv::VideoWriter videoWrite;
// 翻轉操作了
width = width + height;
height = width - height;
width = width - height;
if(!videoWrite.open("1 to 1.avi", CV_FOURCC('M','J','P','G'), 25, cv::Size(width, height)))
{
QMessageBox::warning(0, "保存視頻失敗", "1 to 1.avi");
return;
}
QString version = "v1.2.0";
QString text = QString("OpenCVDemo %1 QQ21497936 blog.csdn.net/qq21497936").arg(version);
for(;;)
{
cv::Mat frame;
videoCapture >> frame;
if(frame.empty())
{
break;
}
// 沿對角線行列翻轉
frame = frame.t();
cv::putText(frame,
cv::String(text.toUtf8().data()),
cv::Point(0, height / 2),
cv::FONT_HERSHEY_SCRIPT_SIMPLEX,
0.8,
cv::Scalar(0,0,255),
3,
8,
false);
cv::imshow("readVideo", frame);
videoWrite << frame;
if(cv::waitKey(1) >= 0)
break;
}
#endif
}
入坑
入坑一:讀取圖片成功,窗口顯示成功,但是圖片顯示失敗
解決方法:使用了中文作爲窗口標題要改爲英文標題
參考引用
《OpenCV入門教程》
工程模板:對應版本號v1.2.0
對應版本號v1.2.0
歡迎技術交流和幫助,提供IT相關服務,索要源碼請聯繫博主QQ: 21497936,若該文爲原創文章,未經允許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100735114