opencv2—(3)遍历图像

我们通过一个例子来简单说明如何遍历图像:减少图像中的颜色数目 CV_8UC3的三通道单字节彩色图像的颜色空间为256*256*256>1600万个,为了降低分析的复杂度,降低颜色数目是有用的。一个简单的算法是把RGB空间划分为同等大小的格子,每个纬度的颜色降低为原来的1/8,那么总的颜色数为32*32*32,原始图像的每个颜色都替换为所在格子中心对应的颜色。
算法实现:
1、采用指针遍历图像,这种操作传入的是源图像的指针,直接对源图像进行修改了
void colorReduce1(cv:: Mat & image , int div = 64)
{
        int nl = image .rows;//行数
        int nc = image .cols;//列数
        for ( int j = 0; j < nl; j++)
       {
               for ( int i = 0; i < nc; i++)
              {
                      image .at<cv:: Vec3b >(j, i) [ 0 ] =
                            image .at<cv:: Vec3b >(j, i) [ 0 ] / div * div + div / 2;
                      image .at<cv:: Vec3b >(j, i) [ 1 ] =
                            image .at<cv:: Vec3b >(j, i) [ 1 ] / div * div + div / 2;
                      image .at<cv:: Vec3b >(j, i) [ 2 ] =
                            image .at<cv:: Vec3b >(j, i) [ 2 ] / div * div + div / 2;
              }
       }
}
为了进行深拷贝,我们可以用
        Mat imageClone = image.clone();
然后把imageClone的引用传入函数,就不会直接对源图像操作了。
当然我们也可以对一个矩阵重新分配确保和原图片一样:
       result.create(image.rows, image.cols, image.type());
我们有另一个版本:
void colorReduce2( const cv:: Mat & image , cv:: Mat & result , int div = 64)
{
        int nl = image .rows;
        int nc = image .cols* image .channels();
        for ( int j = 0; j < nl; j++)
       {
               const uchar * data_in = image .ptr< uchar >(j);
               uchar * data_out = result .ptr< uchar >(j);
               for ( int i = 0; i < nc; i++)
              {
                     data_out[i] = data_in[i] / div * div + div / 2;
              }
       }
}
当然为了高效,图像有可能在行尾扩大了若干个像素,当没有填补时,可以视为W*H的一维数组。通过 image.isContinuous()来判断
void colorReduce3(cv:: Mat & image , int div = 64)
{
        //指针版本
        int nl = image .rows;
        int nc = image .cols* image .channels();
        if ( image .isContinuous())
       {
               //没有进行填补像素
              nc = nc*nl;
              nl = 1;
               //image.reshape(1,image.cols*image.rows);
       }
        for ( int j = 0; j < nl; j++)
       {
               uchar * data = image .ptr< uchar >(j);//获取每一行行首的地址
               for ( int i = 0; i < nc; i++)
              {
                     data[i] = data[i] / div * div + div / 2;
              }
       }
}
当然上面注释部分image.reshape(通道数,行数)也可以重新改变矩阵的维数

2、使用迭代器遍历图像
void colorReduce4(cv:: Mat & image , cv:: Mat & result , int div = 64)
{
        //迭代器版本1
       cv:: Mat_ <cv:: Vec3b >:: iterator it = image .begin<cv:: Vec3b >();
       cv:: Mat_ <cv:: Vec3b >:: iterator itend = image .end<cv:: Vec3b >();
        //迭代器版本2
       cv:: MatIterator_ <cv:: Vec3b > it1 = image .begin<cv:: Vec3b >();
       cv:: MatIterator_ <cv:: Vec3b > it1end = image .end<cv:: Vec3b >();
       cv:: MatIterator_ <cv:: Vec3b > out= result .begin<cv:: Vec3b >();
        for (; it1 != it1end; ++ it1)
       {
              ( * out) [ 0 ] = ( * it) [ 0 ] / div * div + div / 2;
              ( * out) [ 1 ] = ( * it) [ 1 ] / div * div + div / 2;
              ( * out) [ 2 ] = ( * it) [ 2 ] / div * div + div / 2;
       }
}
注意一般图像作为输入时,不让修改,所以回家const修饰,此时迭代器版本也要修改
void colorReduce5( const cv:: Mat & image , cv:: Mat & result , int div = 64)
{
        //迭代器版本1
       cv:: Mat_ <cv:: Vec3b >:: const_iterator it = image .begin<cv:: Vec3b >();
       cv:: Mat_ <cv:: Vec3b >:: const_iterator itend = image .end<cv:: Vec3b >();
        //迭代器版本2
       cv:: MatConstIterator_ <cv:: Vec3b > it1 = image .begin<cv:: Vec3b >();
       cv:: MatConstIterator_ <cv:: Vec3b > it1end = image .end<cv:: Vec3b >();
       cv:: MatIterator_ <cv:: Vec3b > out = result .begin<cv:: Vec3b >();
        for (; it1 != it1end; ++ it1)
       {
              ( * out) [ 0 ] = ( * it) [ 0 ] / div * div + div / 2;
              ( * out) [ 1 ] = ( * it) [ 1 ] / div * div + div / 2;
              ( * out) [ 2 ] = ( * it) [ 2 ] / div * div + div / 2;
       }
}

扩展:统计函数( 或一段代码)的耗费时间的方法
       double duration;
       duration = static_cast < double >(cv::getTickCount());
       {
               //被测试的函数
       }
       duration = static_cast < double >(cv::getTickCount()) - duration;
       duration /= cv::getTickFrequency(); //运行时间,以毫秒为单位

猜你喜欢

转载自blog.csdn.net/sinat_27614619/article/details/54344468