今天看啥
热点:

【从零学习openCV】opecv操作像素,opencvopecv像素


1. 存取像素值


在opencv中可以直接对cv::Mat类型的图像调用at函数读取或赋值某个像素,我们用个简单的案例来说明:
//在一张图像上加入椒盐噪声,image为输入图像,n为噪点个数
void salt(Mat &image, int n)
{
    for(int k = 0;k < n;k++)
    {
        //随机产生白色噪点
        int i = qrand()%image.cols;
        int j = qrand()%image.rows;
        //如果是灰度图每个像素的存取类型为uchar,即8bit整型数
        if(image.channels() == 1){     
            image.at<uchar>(j,i) = 255;
        }
        //彩色图像有三个通道,像素存取类型为cv::Vec3b,即由三个uchar组成的向量,这里用下标[i]访问每个通道
        else{
            image.at<Vec3b>(j,i)[0] = 255;
            image.at<Vec3b>(j,i)[1] = 255;
            image.at<Vec3b>(j,i)[2] = 255;
        }
    }
}
效果如下:

可以看到有很多白色的噪声点,像雪花一样^_^


2. 指针遍历图像

我们用颜色缩减函数来说明用行首地址的方式遍历整个图像的像素,颜色缩减就是将每个通道的颜色数降低,如果每个通道的强度都是有unsigned char表示,那么就有256*256*256个颜色数目,如果将每个通道的颜色数降低为原先的1/8,那个总颜色数就是32*32*32,大概就是这个意思。
//颜色缩减函数,image为输入图像,div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{
    int nl = image.rows; //图像的行数
    //图像每行的像素数
    int nc = image.cols * image.channels();
    for(int j =0;j<nl;j++)
    {
        //得到第j行的首地址
        uchar* data = image.ptr<uchar>(j);
        //遍历每行的像素
        for(int i =0;i<nc;i++)
        {
           data[i] = data[i]/div*div;    //将每个像素值都变为div的倍数,即将颜色数缩减了div倍
        }
    }
}
效果如下:


当输入图像为连续的时候,即没有对图像行尾填补元素,这时就可以将整个图像看成是一个长为W*H的一维数组,即用第一行的行首指针就能遍历到整个图像的像素:
//颜色缩减函数,image为输入图像,div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{
    int nl = image.rows; //图像的行数
    //图像每行的像素数
    int nc = image.cols * image.channels();

    //如果图像连续
    if(image.isContinuous())
    {
        //reshape函数用于改变矩阵维度
        //图像行数为1,列数为原先的行数乘上列数
        image.reshape(1,image.cols*image.rows);
    }

    for(int j =0;j<nl;j++)
    {
        //得到第j行的首地址
        uchar* data = image.ptr<uchar>(j);
        //遍历每行的像素
        for(int i =0;i<nc;i++)
        {
           data[i] = data[i]/div*div;    //将每个像素值都变为div的倍数,即将颜色数缩减了div倍
        }
    }
}

当然opencv还有更为底层的指针,在cv::Mat中,图像数据以unsigned char形式保存在一块内存中。这块内存的首地址可以通过data成员变量得到。data是一个unsigned char型的指针,所以循环可以用以下方式:
    //获得图像指针
    uchar *data  = image.data;
    //获得第j行,第i列个像素值,step代表图像的行宽(包括填补像素)
    data = image.data + j*image.step + i*image.elemSize();


3. 迭代器遍历图像

其实说到遍历,很多人都会想到用迭代器来实现,迭代器是一种特殊的类,专门用来遍历集合中的各个元素,openCV同样为cv::Mat提供了与STL迭代器兼容的迭代器,下面我们还是用颜色缩减为例说明迭代器的使用:
//颜色缩减函数,image为输入图像,div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{
    //得到初始位置的迭代器
    Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
    //得到终止位置的迭代器
    Mat_<Vec3b>::iterator itend = image.end<Vec3b>();
    //遍历所有像素
    for(; it != itend; ++it){
        (*it)[0] = (*it)[0]/div*div;
        (*it)[1] = (*it)[1]/div*div;
        (*it)[2] = (*it)[2]/div*div;
    }
}
效果与用指针遍历的一样。

4. 以上四种存取像素方式效率对比

opencv中可以用getTickCount()来测量一段代码的运行时间,此函数返回从上次开机算起的时钟周期数,getTickFrequency()可以得到每秒内的时钟周期数,有这两个函数就能得到任意一段代码的运行时间了。 我们还是以颜色衰减函数为例,分别用以上四种方法遍历实现,看看运行时间有何不同:
//at方法
void colorReduce1(Mat&image, int div = 64)
{
    int nl = image.rows; //图像的行数
    //图像每行的像素数
    int nc = image.cols * image.channels();
    for(int j =0;j<nl-2;j++)
    {
        for(int i =0;i<nc-2;i++)
        {
            image.at<Vec3b>(j,i)[0] = image.at<Vec3b>(j,i)[0]/div*div;
            image.at<Vec3b>(j,i)[1] = image.at<Vec3b>(j,i)[1]/div*div;
            image.at<Vec3b>(j,i)[2] = image.at<Vec3b>(j,i)[2]/div*div;
        }
    }
}

//行首指针方法
void colorReduce2(Mat&image, int div = 64)
{
    int nl = image.rows; //图像的行数
    //图像每行的像素数
    int nc = image.cols * image.channels();
    for(int j =0;j<nl;j++)
    {
        //得到第j行的首地址
        uchar* data = image.ptr<uchar>(j);
        //遍历每行的像素
        for(int i =0;i<nc;i++)
        {
            data[i] = data[i]/div*div;    //将每个像素值都变为div的倍数,即将颜色数缩减了div倍
        }
    }
}

//一维数组
void colorReduce3(Mat&image, int div = 64)
{
    int nl = image.rows; //图像的行数
    //图像每行的像素数
    int nc = image.cols * image.channels();

    //如果图像连续
    if(image.isContinuous())
    {
        //reshape函数用于改变矩阵维度
        //图像行数为1,列数为原先的行数乘上列数
        image.reshape(1,image.cols*image.rows);
    }

    for(int j =0;j<nl;j++)
    {
        //得到第j行的首地址
        uchar* data = image.ptr<uchar>(j);
        //遍历每行的像素
        for(int i =0;i<nc;i++)
        {
            data[i] = data[i]/div*div;    //将每个像素值都变为div的倍数,即将颜色数缩减了div倍
        }
    }
}

//迭代器方法
void colorReduce4(Mat&image, int div = 64)
{
    //得到初始位置的迭代器
    Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
    //得到终止位置的迭代器
    Mat_<Vec3b>::iterator itend = image.end<Vec3b>();
    //遍历所有像素
    for(; it != itend; ++it){
        (*it)[0] = (*it)[0]/div*div;
        (*it)[1] = (*it)[1]/div*div;
        (*it)[2] = (*it)[2]/div*div;
    }
}

//测试4种像素遍历方式运行时间
void calrunTime(int v,Mat&image)
{
    double duration;
    duration = static_cast<double>(getTickCount());
    for(int i = 0;i<10;i++)   //运行十次取平均值
    {
        switch(v)
        {
        case 1:
            colorReduce1(image);
            break;
        case 2:
            colorReduce2(image);
            break;
        case 3:
            colorReduce3(image);
            break;
        case 4:
            colorReduce4(image);
            break;
        default:
            break;
        }
    }
    duration = static_cast<double>(getTickCount()) - duration;
    duration /= getTickFrequency()/100;        //运行时间,以ms为单位
    qDebug()<<"duration"<<v<<":"<<duration<<"ms";
}



可见用at的方式读取像素效率最低,用迭代器速度也比较慢,效率最高的方式还是使用指针读取。 好了,本篇就到此结束吧,过两天继续更^_^

参考书籍
《openCV2计算机视觉编程手册》
(转载请注明作者和出处:Shawn-HT  http://blog.csdn.net/shawn_ht 未经允许请勿用于商业用途)






我也是opencv初学,想问下你如果要查看图像像素值要怎办

如果已知道像素的坐标就容易了,比如说2维图像,可以用:
cvGet2D(img, x, y);
获得x,y点的像素值
 

opencv检测像素

这个很简单啊:我写段代码你看看
IplImage* src_img = cvLoadImage("图片路径", CV_LOAD_IMAGE_ANYCOLOR);//加载你的原始
//图片
IplImage* gray_img = cvCreateImage( //创建一张单通道的图片用来存放你的灰度图像
cvSize(src_img->width, src_img->height),
src_img->depth,
1
);
cvCvtColor(src_img, gray_img, CV_BGR2GRAY);//将src_img转化为灰度图像(前提是src_img
//是BGR色彩空间的,如果是其他色彩空间的
//话例如hsv的,那么要根据自己的情况选择
//该函数的最后一个参数)

for(int y=0; y<gray_img->height; y++)//迭代出每个像素
{
unchar* ptr = (unchar*)(gray_img->imageData + y*gray_img->widthStep);
for(int x=0; x<gray_img->width; x++)
{
你的数组[数组索引] = ptr[x];//这个ptr[x]就是你要的该像素的灰度色彩值啦,想怎么处
// 理它都可以。
}
}

///////////////////////////////////////////////////////////&......余下全文>>
 

www.bkjia.comtruehttp://www.bkjia.com/ASPjc/908020.htmlTechArticle【从零学习openCV】opecv操作像素,opencvopecv像素 1. 存取像素 在opencv中可以直接对cv::Mat类型的图像调用at函数读取或赋某个像素,我们用个简...

相关文章

相关搜索: 像素 qt4 ubuntu opencv

帮客评论

视觉看点