学习OpenCV(2)OpenCV初探-2
目錄
簡單的變換
不那么簡單的變換
cv::pyrDown()
cv::Canny() & cv::cvtColor()
從攝像頭中讀取
寫入AVI文件
練習
簡單的變換
許多基礎的計算機視覺工作都包括對視頻流使用濾波器。
一個最簡單的操作就是對圖像的平滑處理,這將通過高斯核或者其他核卷積效減小圖像的信息量。
#include <opencv2/opencv.hpp>using namespace std;int main() {cv::namedWindow("Example2-5-in", cv::WINDOW_AUTOSIZE);cv::namedWindow("Example2-5-out", cv::WINDOW_AUTOSIZE);cv::Mat image = cv::imread("./images/girl.jpg");cv::imshow("Example2-5-in", image);cv::Mat out;cv::GaussianBlur(image, out, cv::Size(5, 5), 3, 3);cv::GaussianBlur(out, out, cv::Size(5, 5), 3, 3);cv::imshow("Example2-5-out", out);cv::waitKey();cv::destroyAllWindows();return EXIT_SUCCESS; }實例化一個輸出矩陣out,這將由程序自行管理并在合適的時候自動分配、釋放內存。
將原始圖像輸入到兩個cv::GaussianBlur()函數中,輸入圖像被5*5大小的高斯核模糊并且寫入out中。
注意:高斯核的大小必須時奇數,因為高斯卷積會在其覆蓋區域的中心輸出結果。
不那么簡單的變換
cv::pyrDown()
使用高斯模糊對一張圖像實現基2的降采樣。如果要進行多次的降采樣,就要建立一個尺度空間(圖像金字塔),這一方法是計算機視覺用于處理傳感器和目標尺度變化的常用手段之一。
對信號的降采樣等效于和一系列脈沖函數進行卷積(將這些函數視為“峰值”)。
在OpenCV中,高斯模糊以及降采樣通過 cv::pyrDown()函數來實現。
void cv::pyrDown( InputArray src,OutputArray dst,const Size & dstsize = Size(),int borderType = BORDER_DEFAULT )size of the output image is computed as Size((src.cols+1)/2, (src.rows+1)/2), but in any case, the following conditions should be satisfied:
輸出圖像的大小以公式 Size((src.cols+1)/2, (src.rows+1)/2) 計算所得,但是在任何例子中,下面兩個條件需要被滿足。
//示例2-6 使用cv::pyrDown()來創建一個新的圖像,其寬高均為原始圖像的一半 #include <opencv2/opencv.hpp>using namespace std;int main() {cv::Mat img1, img2;cv::namedWindow("Example1", cv::WINDOW_AUTOSIZE);cv::namedWindow("Example2", cv::WINDOW_AUTOSIZE);img1 = cv::imread("./images/girl.jpg");cv::imshow("Example1", img1);cv::pyrDown(img1, img2);cv::imshow("Example2", img2);cv::waitKey();return EXIT_SUCCESS; }cv::Canny() & cv::cvtColor()
//示例2-7:Canny邊緣檢測器輸出一個單通道的(灰度)圖像 #include <opencv2/opencv.hpp>using namespace std;int main() {cv::Mat img_rgb, img_gry, img_cny;cv::namedWindow("Example_Gray", cv::WINDOW_AUTOSIZE);cv::namedWindow("Example_Canny", cv::WINDOW_AUTOSIZE);img_rgb = cv::imread("./images/girl.jpg");cv::cvtColor(img_rgb, img_gry, cv::COLOR_BGR2GRAY);cv::imshow("Example_Gray", img_gry);cv::Canny(img_gry, img_cny, 10, 100, 3, true);cv::imshow("Example_Canny", img_cny);cv::waitKey();return EXIT_SUCCESS; }cv::Canny()
void cv::Canny(inputArray, //image:輸入圖像(8-bit)outputArray, //edges:輸出圖像(單通道,8-bit,size與輸入圖像一致)double, //threshold1:閾值1double, //threshold2:閾值2int, //apertureSize = 3: Sober算子大小bool //L2gradient = false:是否采用更精確的方式計算圖像梯度);void cv::Canny(inputArray, //dx:輸入圖像在x方向的導數:16-bit(CV_16SC1 & CV_16SC3)inputArray, //dy:輸入圖像在y方向的導數:16-bit(CV_16SC1 & CV_16SC3)outputArray, //edges:輸出邊緣圖像(單通道,8-bit,size與輸入圖像一致)double, //threshold1:閾值1double, //threshold2:閾值2bool //L2gradient = false:是否采用更精確的方式計算圖像梯度);關于閾值:小于 閾值1 不是邊緣,介于閾值1與閾值2之間的是弱邊緣,大于閾值2的是強邊緣
關于L2gradient參數:
如果為true,計算圖像梯度的時候會使用:(更加準確)
如果是false,計算圖像梯度的時候使用:
//示例2-8:在一個簡單圖像處理流程中結合圖像金字塔操作(兩次)和Canny邊緣檢測器 //示例2-9:讀寫示例2-8的像素值 #include <iostream> #include <opencv2/opencv.hpp>using namespace std;int main() {cv::Mat img_rgb, img_gry, img_cny, img_pyr, img_pyr2;cv::namedWindow("Example_Gray", cv::WINDOW_AUTOSIZE);cv::namedWindow("Example_Canny", cv::WINDOW_AUTOSIZE);img_rgb = cv::imread("./images/girl.jpg");cv::cvtColor(img_rgb, img_gry, cv::COLOR_BGR2GRAY);cv::pyrDown(img_gry, img_pyr);cv::pyrDown(img_pyr, img_pyr2);cv::Canny(img_pyr2, img_cny,10, 100, 3, true);int x = 16, y = 32;cv::Vec3b intensity = img_rgb.at<cv::Vec3b>(y, x);uchar blue = intensity[0];uchar green = intensity[1];uchar red = intensity[2];cout << "At(x, y) = (" << x << "," << y << "):(blue, green, red) = (" << (unsigned int)blue << ","<< (unsigned int)green << "," << (unsigned int)red << ")" << endl;cout << "Gray pixel there is : " << (unsigned int)img_gry.at<uchar>(y, x) << endl;x /= 4;y /= 4;cout << "Gray pixel there is : " << (unsigned int)img_gry.at<uchar>(y, x) << endl;img_cny.at<uchar>(x, y) = 128;cv::waitKey();return EXIT_SUCCESS; }從攝像頭中讀取
OpenCV的HighGui模塊提供了攝像頭接口。
使用cv::VideoCapture()從硬盤讀取視頻和攝像頭有一致的接口。
????????對于前者:只需要提供讀取文件的路徑
????????對于后者:需要給它一個相機ID號(如果只有一個攝像頭連接,這個ID號通常是0),ID的默認是-1,意味著 隨意選擇一個攝像頭。
#include <iostream> #include <string> #include <stdlib.h> #include <opencv2/opencv.hpp>using namespace std;int main() {cv::namedWindow("Example2_10", cv::WINDOW_AUTOSIZE);cv::VideoCapture cap;cap.open(0);cv::Mat frame;if (!cap.isOpened()){cout << "Couldn't open capture!" << endl;return -1;}while (1){cap >> frame;if (frame.empty()){cout << "圖片寫入失敗" << endl;return -1;}cv::imshow("Example2_10", frame);if (cv::waitKey(33) >= 0) //手動退出,任意鍵退出{break;}}cv::destroyAllWindows();return EXIT_SUCCESS; }寫入AVI文件
創建一個寫入對象以便將幀依次輸入到一個視頻文件中,允許我們進行這個工作的對象是cv::VideoWriter.
一旦將其實例化,可以將每一幀圖像輸入到cv::VideoWriter對象中,在完成寫入之后調用cv::VideoWriter.release()方法。
//示例2-11:一個完整的讀取彩色視頻并轉換為對數極坐標視頻的程序 #include <iostream> #include <opencv2/opencv.hpp>using namespace std;int main() {cv::namedWindow("Example2_11", cv::WINDOW_AUTOSIZE);cv::namedWindow("Log_Polar", cv::WINDOW_AUTOSIZE);cv::VideoCapture cap;cap.open("./images/bike.avi");double fps = cap.get(cv::CAP_PROP_FPS);cv::Size size((int)cap.get(cv::CAP_PROP_FRAME_WIDTH),(int)cap.get(cv::CAP_PROP_FRAME_HEIGHT));cv::VideoWriter writer;writer.open("log_bike.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, size, true);//注意writer寫入文件的名稱,需要加上后綴名cv::Mat logpolar_frame, bgr_frame;while (1){cap >> bgr_frame;if (bgr_frame.empty()){break;}cv::imshow("Example2_11", bgr_frame);cv::logPolar(bgr_frame,logpolar_frame,cv::Point2f(bgr_frame.cols/2,bgr_frame.rows/2),40,cv::WARP_FILL_OUTLIERS);cv::imshow("Log_Polar", logpolar_frame);writer << logpolar_frame;char c = cv::waitKey(33);if (c == 27){break;}}cap.release();return EXIT_SUCCESS; }cv::VideoWriter的調用參數:
第一個參數是新建視頻文件的文件名;
第二個參數是視頻編碼方式,指明視頻將以何種方式進行壓縮;
第三個參數是視頻的幀率;
第四個參數是視頻的Size。
cv::logPolar的調用參數:Log-polor轉換表示從笛卡爾坐標到極坐標的變換
void cvLogPolar( const CvArr* src, //輸入圖像CvArr* dst, //輸出圖像CvPoint2D32f center, //變換的中心,輸出圖像在這里最清晰double M, //幅度的尺度參數int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );flags:插值方法和以下選擇標志的結合
CV_WARP_FILL_OUTLIERS -填充輸出圖像所有像素,如果這些點有和外點對應的,則置零。
CV_WARP_INVERSE_MAP - 表示矩陣由輸出圖像到輸入圖像的逆變換,并且因此可以直接用于像素插值。否則,函數從map_matrix中尋找逆變換。
練習
3、將示例2-11和2-6中的代碼連接起來,建立一個讀取視頻并存儲降采樣后的彩色圖像的程序。
4、修改練習3中的代碼,并結合示例2-2中窗口顯示的代碼來顯示處理的圖像
#include <iostream> #include <string> #include <stdlib.h> #include <opencv2/opencv.hpp>using namespace std; int main() {cv::namedWindow("Example2_11", cv::WINDOW_AUTOSIZE);cv::namedWindow("pyr_image", cv::WINDOW_AUTOSIZE);cv::VideoCapture cap;cap.open("./images/bike.avi");double fps = cap.get(cv::CAP_PROP_FPS);cv::Size size((int)cap.get(cv::CAP_PROP_FRAME_WIDTH),(int)cap.get(cv::CAP_PROP_FRAME_HEIGHT));cv::VideoWriter writer;writer.open("log_bike_pyr.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, size, true);cv::Mat pyr_frame, bgr_frame;while (1){cap >> bgr_frame;if (bgr_frame.empty()){break;}cv::imshow("Example2_11", bgr_frame);cv::pyrDown(bgr_frame, pyr_frame);cv::imshow("pyr_image", pyr_frame);writer << pyr_frame;char c = cv::waitKey(33);if (c == 27){break;}}cap.release();return EXIT_SUCCESS; }5、修改4,添加一個示例2-4中的滑動條,用戶可以動態控制金字塔的降采樣等級(從2-8)。可以跳過存儲的步驟,但要將處理結果顯示出來。
//問題:進度條的數字不能隨進度條的改變而改變,初始程序無法自動播放視頻,需要手動點擊進度條,由于能力有限,僅完成以下部分。 #include <iostream> #include <string> #include <stdlib.h> #include <opencv2/opencv.hpp>using namespace std;int g_slider_position = 2; int g_old_position = 2; bool g_dontset = false; cv::VideoCapture g_cap; cv::Mat pyr_frame, bgr_frame; int g_frames; int n = 0;void onTrackbarSlide(int pos, void*) {while (1){if (g_old_position != g_slider_position){g_old_position = g_slider_position;cv::destroyWindow("pyr_image");cv::namedWindow("pyr_image", cv::WINDOW_AUTOSIZE);}if (n == g_frames - 1){g_cap.set(CV_CAP_PROP_POS_FRAMES, 1);n = 0;}n++;g_cap >> bgr_frame;if (bgr_frame.empty()){break;}cv::imshow("Example2_11", bgr_frame);for (int i = 1; i < pos; i++){cv::pyrDown(bgr_frame, bgr_frame);}cv::imshow("pyr_image", bgr_frame);char c = cv::waitKey(33);if (c == 27){break;}} }int main() {cv::namedWindow("Example2_11", cv::WINDOW_AUTOSIZE);cv::namedWindow("pyr_image", cv::WINDOW_AUTOSIZE);g_cap.open("./images/bike.avi");double fps = g_cap.get(cv::CAP_PROP_FPS);cv::Size size((int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH),(int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT));int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);int tmpw = (int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH);int tmph = (int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT);g_frames = frames;cv::createTrackbar("Position", "Example2_11", &g_slider_position, 8, onTrackbarSlide);cv::waitKey();return EXIT_SUCCESS; }總結
以上是生活随笔為你收集整理的学习OpenCV(2)OpenCV初探-2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英才计划计算机潜质测评试题,湖北省202
- 下一篇: Unraveling the JPEG