日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

cv mat保存图片_(七)神秘的Mat

發布時間:2025/3/15 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 cv mat保存图片_(七)神秘的Mat 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

時間為友,記錄點滴。

不知道你有沒有跟我一樣,看到一些關鍵的類或結構體總想看看他的結構是什么?因為我覺得單單知其然是不夠的,知其所以然才能走得更遠。

雖然我們只寫了兩個例子,但是很明顯,這里面的核心內容是Mat類。

The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms (though, very high-dimensional histograms may be better stored in a SparseMat ).
上面的一段話引用自官方的文檔,Mat類用于表示一個多維的單通道或者多通道的稠密數組。能夠用來保存實數或復數的向量、矩陣,灰度或彩色圖像,立體元素,點云,張量以及直方圖(高維的直方圖使用SparseMat保存比較好)。簡而言之,Mat就是用來保存多維的矩陣的。

如果你在mat.hpp中點開Mat的類定義,估計要被它一長長串的構造函數和重載看崩潰,我們直接略過令人崩潰的地方(在實際使用中,常用的定義一個Mat類型的對象的方法就那幾個),看到下面的成員變量:

  • data:

uchar型的指針。Mat類分為了兩個部分:矩陣頭和指向矩陣數據部分的指針,data就是指向矩陣數據的指針。

  • dims:

矩陣的維度,例如5*6矩陣是二維矩陣,則dims=2,三維矩陣dims=3.

  • rows:

矩陣的行數

  • cols:

矩陣的列數

  • size:

矩陣的大小,size(cols,rows),如果矩陣的維數大于2,則是size(-1,-1)

  • channels:

矩陣元素擁有的通道數,例如常見的彩色圖像,每一個像素由BGR三部分組成,則channels = 3。

  • type:

表示了矩陣中元素的類型以及矩陣的通道個數,它是一系列的預定義的常量,其命名規則為CV_(位數)+(數據類型)+(通道數)。這里U(unsigned integer)表示的是無符號整數,S(signed integer)是有符號整數,F(float)是浮點數。

例如:CV_16UC2,表示的是元素類型是一個16位的無符號整數,通道為2. C1,C2,C3,C4則表示通道是1,2,3,4。type一般是在創建Mat對象時設定,如果要取得Mat的元素類型,則無需使用type,使用下面的depth

輸出的數值,對照表
  • depth

矩陣中元素的一個通道的數據類型,這個值和type是相關的。例如 type為 CV_16SC2,一個2通道的16位的有符號整數。那么,depth則是CV_16S。depth也是一系列的預定義值,
將type的預定義值去掉通道信息就是depth值:
CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F

  • elemSize

矩陣一個元素占用的字節數,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes

  • elemSize1

矩陣元素一個通道占用的字節數,例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels

如何創建一個Mat也有好多中方法(我最常用的就是下面這三種):

  • Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
  • Mat Z = Mat::zeros(3, 3, CV_64F);Mat F = Mat::ones(2, 2, CV_64F);Mat F = Mat::ones(2, 2, CV_64F);
  • Mat M = (Mat_<double>(3, 3) << 0, 1, 2, 1, 2, 3, 2, 3, 4) ;
  • 多說無益,我們用代碼來驗證,可以寫一個函數來把img的各個參數打印出來:

    現有圖片測試

    static void showImgPara(Mat &img) {cout << "sizeof(img) is: " << sizeof(img) << ", img size is: " << img.size << endl;cout << "rows x cols: (" << img.rows << " x " << img.cols << ")" << endl;cout << "dims: " << img.dims << endl;cout << "channels: " << img.channels() << endl;cout << "type: " << img.type() << endl;cout << "depth:" << img.depth() << endl;cout << "elemSize:" << img.elemSize() << " (Bytes per element)" << endl;cout << "elemSize1:" << img.elemSize1() << "(Bytes per channel)" << endl;cout << "step[0]: " << img.step[0] << " (Bytes per cows only when 2 dims)" << endl;cout << "step[1]: " << img.step[1] << " (Bytes per element only when 2 dims)" << endl;cout << "step1(0): " << img.step1(0) << ", step1(1): " << img.step1(1) << " (step / elemSize1)" << endl; } static bool pictureTest(Mat &img, string name) {if (img.empty()){cout << "Load picture fail!" << endl;return false;}cout << endl << "/******************pictureTest******************/" << endl;showImgPara(img);namedWindow(name);imshow(name, img);return true; }int main() {Mat pic = imread("girl.jpg");pictureTest(pic, "girl");waitKey(0);return 0; }

    運行結果

    自建Mat類型:

    除了看自己創建Mat對象的一些屬性,主要考量把自建對象的數據dump出來,可以看到使用了step。

    static bool matTest(Mat &img) {uchar* pTemp = NULL;cout << endl << "/******************matTest******************/" << endl;cout << img << endl;showImgPara(img);for (int i = 0; i < img.rows; i++){for(int j = 0; j < img.cols; j++){cout << "[";for (int k = 0; k < img.step[1]; k++){pTemp = img.data + img.step[0] * i + img.step[1] * j + k;cout << (int)*pTemp << " ";}cout << "] ";}cout << endl;}return true; }

    創建一個3行4列, 每個元素是8bit(unsigned char),包含兩個通道,并且初始化為[1, 2]

    int main() {Mat m2(3, 4, CV_8UC2, Scalar_<uchar>(1, 2));matTest(m2);waitKey(0);return 0; }

    matTest

    隨意創建一張涂色圖片

    我們除了提前給data賦值,也可以通過data指針修改圖像中的任意像素。比如下圖可以修改創建圖片的中間方塊為任意顏色(本例子中全部涂黑),并且通過imshow直觀的體現出來。

    static bool picCreat(Mat &img, string name) {for (int i = 0; i < img.rows; i++){uchar *p = img.ptr<uchar>(i);for (int j = 0; j < img.cols * img.channels(); j += img.channels()){if (i > img.rows/4 && i < img.rows*3/4 && j > img.cols*img.channels()/4 && j < img.cols*img.channels()*3/4){p[j] = 0;p[j + 1] = 0;p[j + 2] = 0;}else{p[j] = 255;p[j + 1] = 255;p[j + 2] = 255;}}}cout << endl << "/******************picCreat******************/" << endl;showImgPara(img);namedWindow(name);imshow(name, img);return true; }

    創建一個200x300大小的圖片。

    int main() {Mat m1 = Mat::zeros(200, 400, CV_8UC3);picCreat(m1, "White");waitKey(0);return 0; }

    通過填充數據的方法生成一張中間是黑色的圖片

    picCreate

    圖片導成文件

    為了肉眼觀測方便,實現了一個多通道轉單通道的函數。(暴力得是把第一個通道的數據取出來)

    static bool tran2singleChannel(Mat &src, Mat &tar) {vector<Mat> channels;split(src, channels);tar = channels.at(0);return true; }

    把一個任意圖片,轉換成單通道,把data dump出來,存在文件中。

    static bool pic2digit(Mat &img, string picName, string fileName) {uchar* pTemp = NULL;Mat signalChannel;ofstream output;if (img.empty()){cout << "Load picture fail!" << endl;return false;}cout << endl << "/******************pic2digit******************/" << endl;//showImgPara(img);//namedWindow(picName);//imshow(picName, img);tran2singleChannel(img, signalChannel);//namedWindow(picName + "_signalChannel");//imshow(picName + "_signalChannel", signalChannel);showImgPara(signalChannel);output.open(fileName);for (int i = 0; i < signalChannel.rows; i++){for (int j = 0; j < signalChannel.cols; j++){for (int k = 0; k < signalChannel.step[1]; k++){pTemp = signalChannel.data + signalChannel.step[0] * i + signalChannel.step[1] * j + k;output << setw(2) << setfill('0') << (int)*pTemp << " ";}}output << endl;}output.close();imwrite(picName + "_signalChannel.jpg", signalChannel);return true; }

    照一張簡單的對勾圖片

    int main() {Mat pic1 = imread("check-circle.png");pic2digit(pic1, "check", "check-circle.txt");waitKey(0);return 0; }

    pic2digit

    生成的文件,跟原圖比輪廓一致

    全部代碼:

    #include <opencv2/opencv.hpp> #include <iostream> #include <string> #include <fstream>using namespace std; using namespace cv;static void showImgPara(Mat &img); static bool pictureTest(Mat &img, string name); static bool matTest(Mat &img); static bool picCreat(Mat &img, string name); static bool pic2digit(Mat &img, string picName, string fileName); static bool tran2singleChannel(Mat &src, Mat &tar);int main() {Mat pic = imread("girl.jpg");pictureTest(pic, "girl");Mat m1 = Mat::zeros(200, 400, CV_8UC3);picCreat(m1, "White");Mat m2(3, 4, CV_8UC2, Scalar_<uchar>(1, 2));matTest(m2);Mat pic1 = imread("check-circle.png");pic2digit(pic1, "check", "check-circle.txt");waitKey(0);return 0; }static void showImgPara(Mat &img) {cout << "sizeof(img) is: " << sizeof(img) << ", img size is: " << img.size << endl;cout << "rows x cols: (" << img.rows << " x " << img.cols << ")" << endl;cout << "dims: " << img.dims << endl;cout << "channels: " << img.channels() << endl;cout << "type: " << img.type() << endl;cout << "depth:" << img.depth() << endl;cout << "elemSize:" << img.elemSize() << " (Bytes per element)" << endl;cout << "elemSize1:" << img.elemSize1() << "(Bytes per channel)" << endl;cout << "step[0]: " << img.step[0] << " (Bytes per cows only when 2 dims)" << endl;cout << "step[1]: " << img.step[1] << " (Bytes per element only when 2 dims)" << endl;cout << "step1(0): " << img.step1(0) << ", step1(1): " << img.step1(1) << " (step / elemSize1)" << endl; }static bool pictureTest(Mat &img, string name) {if (img.empty()){cout << "Load picture fail!" << endl;return false;}cout << endl << "/******************pictureTest******************/" << endl;showImgPara(img);namedWindow(name);imshow(name, img);return true; }static bool matTest(Mat &img) {uchar* pTemp = NULL;cout << endl << "/******************matTest******************/" << endl;cout << img << endl;showImgPara(img);for (int i = 0; i < img.rows; i++){for(int j = 0; j < img.cols; j++){cout << "[";for (int k = 0; k < img.step[1]; k++){pTemp = img.data + img.step[0] * i + img.step[1] * j + k;cout << (int)*pTemp << " ";}cout << "] ";}cout << endl;}return true; }static bool picCreat(Mat &img, string name) {for (int i = 0; i < img.rows; i++){uchar *p = img.ptr<uchar>(i);for (int j = 0; j < img.cols * img.channels(); j += img.channels()){if (i > img.rows/4 && i < img.rows*3/4 && j > img.cols*img.channels()/4 && j < img.cols*img.channels()*3/4){p[j] = 0;p[j + 1] = 0;p[j + 2] = 0;}else{p[j] = 255;p[j + 1] = 255;p[j + 2] = 255;}}}cout << endl << "/******************picCreat******************/" << endl;showImgPara(img);namedWindow(name);imshow(name, img);return true; }static bool pic2digit(Mat &img, string picName, string fileName) {uchar* pTemp = NULL;Mat signalChannel;ofstream output;if (img.empty()){cout << "Load picture fail!" << endl;return false;}cout << endl << "/******************pic2digit******************/" << endl;//showImgPara(img);//namedWindow(picName);//imshow(picName, img);tran2singleChannel(img, signalChannel);//namedWindow(picName + "_signalChannel");//imshow(picName + "_signalChannel", signalChannel);showImgPara(signalChannel);output.open(fileName);for (int i = 0; i < signalChannel.rows; i++){for (int j = 0; j < signalChannel.cols; j++){for (int k = 0; k < signalChannel.step[1]; k++){pTemp = signalChannel.data + signalChannel.step[0] * i + signalChannel.step[1] * j + k;output << setw(2) << setfill('0') << (int)*pTemp << " ";}}output << endl;}output.close();imwrite(picName + "_signalChannel.jpg", signalChannel);return true; }static bool tran2singleChannel(Mat &src, Mat &tar) {vector<Mat> channels;split(src, channels);tar = channels.at(0);return true; }

    check-circle.png

    girl.jpg

    寫在后面:

    Mat類中有兩個數據部分組成:

    • 矩陣頭:包括矩陣尺寸、存儲方法、存儲地址等。
    • 指針:該指針指向存儲所有像素值的矩陣。

    因為圖片的數據量比較大,所以OpenCV中的Mat定義都是只申請了矩陣頭和指針,盡量避免對指針指向的內容進行拷貝操作,所以如下操作都是共享的數據:

    Mat A, C; // Identify header onlycout << "sizeof(A): " << sizeof(A) << "; sizeof(C): " << sizeof(C) << endl;cout << "A:n" << A << endl;A = Mat::ones(Size(3, 3), CV_8UC1);C = A;cout << "sizeof(A): " << sizeof(A) << "; sizeof(C): " << sizeof(C) << endl;cout << "A:n" << A << endl;Mat B(A);cout << "B:n" << B << endl;B.at<uchar>(1, 1) = 255;cout << "C:n" << C << endl;Mat D = A.clone();cout << "D:n" << D << endl;D.at<uchar>(0, 0) = 123;cout << "A:n" << A << endl;cout << "D:n" << D << endl;Mat E;A.copyTo(E);cout << "E:n" << E << endl;E.at<uchar>(2, 2) = 100;cout << "A:n" << A << endl;cout << "E:n" << E << endl;

    所以,關于Mat類型的變量定義以及賦值分為:

    公用一個數據塊:

    • =
    • 構造函數

    不公用一個數據塊:

    • clone
    • copyto

    總結

    以上是生活随笔為你收集整理的cv mat保存图片_(七)神秘的Mat的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 狂野少女电影在线观看国语版免费 | av网址导航| 青青草视频在线观看 | 国产三级播放 | 超碰午夜| 肉嫁高柳在线 | 亚洲20p| av网页在线| 免费毛片小视频 | 国产午夜精品免费一区二区三区视频 | 四虎新网址 | 精品国产av色一区二区深夜久久 | 久久伊人久久 | 亚洲在线观看一区二区 | 亚洲福利视频一区二区 | 国产激情a | 成人a在线观看 | 福利视频三区 | 黄色三级在线观看 | c逼| 免费观看一级视频 | 男同av在线观看一区二区三区 | 美女自拍偷拍 | 91性高潮久久久久久久久 | 日韩免费视频一区二区视频在线观看 | 午夜伦理影院 | 双乳被四个男人吃奶h文 | 久久亚洲AV成人无码国产人妖 | 亚洲区久久| 少妇极品熟妇人妻无码 | 老头av | 丰腴饱满的极品熟妇 | 亚洲50p| 黑人干亚洲女人 | babes性欧美69 | 91黄色视屏 | 久久精品国产亚洲av麻豆 | 国产热99 | 女人洗澡一级特黄毛片 | 可以免费看的黄色网址 | 91精品国产一区 | 人碰人操| www.色网 | 青青草原国产 | 一级二级毛片 | 国产一二三区在线视频 | 秋霞三区 | 老熟妇一区二区三区啪啪 | 天堂资源在线播放 | 亚洲精品国产精品乱码 | 黄频在线播放 | 四虎免费观看 | 亚洲第九十九页 | 日本欧美视频 | a毛片网站| 国产视频1区2区3区 国产欧美一区二区精品性色99 | 日韩免费高清视频 | 国产免费久久精品国产传媒 | 午夜小视频在线播放 | 久久噜噜色综合一区二区 | 五月激情婷婷综合 | 国产又粗又长又大 | 亚洲一区二区成人 | 亚洲国产精品成人无码区 | 亚洲精品97久久中文字幕 | 在线看国产视频 | 亚洲精品视频专区 | 国产一区视频在线 | 日本一二三不卡视频 | 中文字幕在线观看的网站 | 3d动漫精品啪啪一区二区三区免费 | 成人精品视频一区二区 | 97在线国产 | 96av在线| 男人的天堂日韩 | 青青草免费公开视频 | 亚洲天堂一区 | 妖精视频在线观看免费 | 天天干 夜夜操 | 伊人久久大香线蕉成人综合网 | 国外成人性视频免费 | 麻豆精品在线观看 | 亚洲黄色视屏 | 精品人妻一区二区免费 | 一级片一级 | 老司机午夜精品视频 | 亚洲日本视频 | 国产crm系统91在线 | 玖玖视频 | 哪里可以看免费毛片 | 美女隐私无遮挡网站 | 在线手机av| 午夜在线视频播放 | 日本一区二区精品 | 成长快手短视频在线观看 | 亚洲国产毛片aaaaa无费看 | 欧美日韩免费一区二区 | 成人久久免费视频 | 成人欧美一区二区三区在线观看 |