与OpenCV的第六天

第一件事:访问图像中的像素

1. 图像的数据,是如何以指定的颜色空间和数据类型存储在内存中的?

同一个图像的矩阵的大小取决于所用的颜色空间和数据类型,确切的说取决于通道数和深度。

灰度空间矩阵:

灰度矩阵排列

RGB空间矩阵:

RGB矩阵排列

可以发现 OpenCV 在内存中子列的通道顺序与通常习惯的 RBG 顺序相反——BGR。通常内存足够的情况下,可以实现图像在内存中的连续存储,这样极大地提高了图像的扫描速度,可以使用 isContinuous() 函数来判断矩阵在内存中是否为连续存储。

2. 颜色空间缩减

若图像是单通道的并且使用 8 位字符类型,那么一个像素位置可能有256个不同值,那么如果有三通道呢?那么一个像素位置将会有一千六百多万种可能颜色,若果我们队这些颜色进行逐一分类处理的话那么将对我们算法性能造成极其严重的影响。所以我们需要对颜色空间进行一些缩减,比如颜色值 0-9 的按0计算,10-19 的按10计算,以此类推。
在对整形 "/" 运算中,会自动去掉余数那么我们可以这样操作简单地实现上面的需求:

int b = 13;
int a = (b/10)*10 = (13/10)*10 = 1*10 = 10;

但是如果每一次都对每个像素进行这样的计算过程,也是需要很大的时间花销,而且这两种运算(乘、除)又特别费时。我们可以先将像素的可能性存在表中,需要用的时候直接从表里面取出来即可。

//先存在表里面
int divideWidth = 10;
uchar table[256];
for (int i = 0,i < 256;i++){
    table[i] = divideWidth * (i/divideWidth);
}

//查找对应值
int key = 111;
int value = table[key];

3. LUT 函数:生成缩减矩阵

在上一点中生成了一个查找表,用来查找某个通道对应的缩减值而非每次都进行计算。接下来我们就需要将目标图像矩阵进行缩减生成缩减图像,思路是:

  1. 先生成查找表;
  2. 遍历目标矩阵每一个元素;
  3. 将目标矩阵中每一个元素在查找表中找到对应缩减值;
  4. 将缩减值存入新的矩阵。

很快就写出了代码。但是!之前又讲到OpenCV是一个开发 工具 包,作为工具包这点事情都不能帮我们轻松解决还算什么工具包?所以OpenCV中为我们封装了一个函数,并且这个函数OpenCV官方文档中是极力推荐我们使用的,那就是 LUT 函数,函数原型:

void LUT(InputArray src, InputArray lut, OutputArray dst);
参数 意义
InputArray src 源矩阵
InputArray lut 查找表
OutputArray dst 输出矩阵

示例程序:

    //建立查找表
    int div = 100;//值大一点效果比较明显
    
    //LUT 函数中需要输入的是一个InputArray类型
    cv::Mat luTable(1,256, CV_8U);
    uchar* table = luTable.data;
    for (int i = 0; i < 256; i++) {
        table[i] = div * (i/div);
    }
    
    cv::Mat srcImage = cv::imread("/Users/wangxin/Desktop/1.jpg");
    cv::Mat dstImage;
    
    cv::LUT(srcImage, luTable, dstImage);
    cv::imshow("srcImage", srcImage);
    cv::imshow("dstImage", dstImage);
    cv::waitKey();

运行效果图【原图】
运行效果图【缩减图】

4. 计时函数

可以利用 getTickCount()getTickFrequency 函数来进行计时。

  • getTickCount 函数:该函数返回CPU自某个时间以来所经历的时间周期数。
  • getTickFrequency() 函数:该函数返回CPU一秒钟走的时钟周期数。这样我们就可以对某个运算进行计时了。
//起始状态的时间周期
double time0 = static_cast<double>(cv::getTickCount());

//图像处理操作
//~

//结束时的时间周期数
double time1 = static_cast<double>(cv::getTickCount());double 
//计算得出花费时间
time = (time1 - time0)/cv::getTickFrequency;
//输出运行时间
cout<< "此方法运行时间为:" << time << "秒" << endl;

5. 访问像素的三种方法

  • 指针访问:C操作符[];(最快)
    核心代码:
int rowNumber = image.rows;
//列数*通道数
int colNumber = image.cols*image.channels();
//循环遍历像素
for(int i = 0; i < rowNumber; i++){
    uchar* data = image.ptr<uchar>(i);//获取第i行首地址
    for(int j = 0; j < colNUmber; j++){
          //处理像素
          data[j];
    }
}
  • STL 中的迭代器 iterator(慢)
    核心代码:
Mat_<Vec3b>::iterator it = outputImage.begen<Vec3b>();//初始位置
Mat_<Vec3b>::iterator itend = outputImage,end<Vec3b>();//结束位置
for(;it != itend;it++){
    //开始处理每个像素
    (*it)[0];//通道1,蓝色通道
    (*it)[1];//通道2,绿色通道
    (*it)[2];//通道3,红色通道
}
  • 动态地址计算(最慢)
    利用 at 函数
    核心代码:
int rowNumber = image.rows;
//列数*通道数
int colNumber = image.cols;
//循环遍历像素
for(int i = 0; i < rowNumber; i++){
    for(int j = 0; j < colNUmber; j++){
          //处理像素
          image.at<Vec3b>(i,j)[0];//通道1,蓝色通道
          image.at<Vec3b>(i,j)[1];//通道2,绿色通道
          image.at<Vec3b>(i,j)[2];//通道3,红色通道
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容