OpenCV2 && Qt4 chapter2: Manipulating the Pixels

最近事情好多呀,又是ACM省赛,又是两个大课程设计,又是线代挂科的重考。又是dota,又是看视频什么的。哈哈。忙里偷闲地看完了第二章。大概地记录一下:

OpenCV2:

1. copyTo 和 clone都是深复制。已经经过实验。

cv::Mat_<Tp> 是cv::Mat的子类,并且是模板类,定义时就必须指定类型。挺好用的~~

2. 像素点的访问 (盐椒噪声的模拟)

用 cv::Mat 的at<Tp>函数或者用 cv::Mat_<Tp>的()函数。 两个访问得到的都是像素点,像素点是一个vector对象,里面放着各通道的值。 两个函数都要知道图像的类型。

void salt(cv::Mat &img,int n)        //img是浅复制哟。。不过加上&引用更加好理解
{
    int i,j;
   qsrand(0);
   while(n--)
   {
       i = qrand()% img.rows;
       j=  qrand()% img.cols;

       if(img.channels() == 3)
       {
           // cv::Vec3b   a vector of 3 uchar. color image type.
           // typedef Vec<uchar, 3> Vec3b;  Vec是模板类 channels = cn。  通道为3
           //  template<typename _Tp> _Tp& at

           img.at<cv::Vec3b>(i,j)[0]=255;
           img.at<cv::Vec3b>(i,j)[1]=255;
           img.at<cv::Vec3b>(i,j)[2]=255;
       }
   }
}

3. 像素点遍历。 (图像的压缩)

图像的压缩算法: 通道值 t=t/div*div+div/2;   好神奇,不明白。反正就是能压缩。

1>用指针访问通道。

void colorReduce(cv::Mat &img1,int div=64)
{
    int i,j;
    uchar *p;
    for(i=0;i<img1.rows;++i)
    {
        p = img1.ptr<uchar>(i);
        // 一个像素点应该是 长度为3的vec结构~
        for(j=0;j<img1.cols*img1.channels();++j)
            p[j] = p[j]/div*div+div/2;

    }
}

2>用迭代器访问像素。

void fun(cv::Mat &image,int div=64)
{
    // 也可以 cv::Mat_<cv::Vec3b>::iterator it;
    cv::MatIterator_<cv::Vec3b> it=image.begin<cv::Vec3b>();
    cv::MatIterator_<cv::Vec3b> itend=image.end<cv::Vec3b>();
    while(it != itend)
    {
          (*it)[0]= (*it)[0]/div*div+div/2;
          (*it)[1]= (*it)[1]/div*div+div/2;
          (*it)[2]= (*it)[2]/div*div+div/2;
          ++it;
    }
}

最效率:

最快的遍历+压缩: 遍历用指针,压缩用位运算。image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2);


4.相邻像素点处理。(图像锐化)

锐化算法: sharpen_pixel = 5*cur-left-right-up-down

1>指针访问通道:

只能处理单通道的。多通道的麻烦。

2> cv::filter2D函数。 矩阵过滤处理函数。 可以处理多通道的图像。 kernel矩阵要做好初始化。

void fun(cv::Mat &image,cv::Mat &res)
{
    /*
    //  只能是处理黑白图像,单通道型的。
    res.create(image.size(),image.type());
    for(int i=1;i<image.rows-1;++i)
    {
        uchar *pre=image.ptr<uchar>(i-1);
        uchar *cur=image.ptr<uchar>(i);
        uchar *next=image.ptr<uchar>(i+1);

        uchar *output=res.ptr(i);
        for(int j=1;j<image.cols*image.channels();++j)
        {
            // saturate_cast 饱和转换,限定范围在0-255
            output[j] = cv::saturate_cast<uchar>( 5*(cur[j]) -cur[j]-pre[j]-next[j]-cur[j-1]-cur[j+1]);
        }
    }
  / */
    // 通用的矩阵处理,多通道也是OK的哟。
    cv::Mat kernel(3,3,CV_32F,cv::Scalar(0));
    kernel.at<float>(1,1)=5.0;
    kernel.at<float>(0,1)=-1.0;
    kernel.at<float>(2,1)=-1.0;
    kernel.at<float>(1,0)=-1.0;
    kernel.at<float>(1,2)=-1.0;
    cv::filter2D(image,res,image.depth(),kernel);

}
5. 图像与图像间的数学运算 (加减乘除都有,以加法为例。 图像添加水印)

1>除了copyTo,其它函数均要求 图像的size相同。 如果不同,可以如下解决:

cv::Mat image2 = image1( cv::Rect(0,0,logo.cols,logo.rows) );    这样子 image2的size就和logo相同,且位置在image的左上角上,注意是浅复制哟。

2. 几个函数的说明。

a[i] b[i] c[i] 必须是一样大小。
// c[i]= a[i]+b[i];
cv::add(imageA,imageB,resultC);
// c[i]= a[i]+k;
cv::add(imageA,cv::Scalar(k),resultC);
// c[i]= k1*a[1]+k2*b[i]+k3;
cv::addWeighted(imageA,k1,imageB,k2,k3,resultC);
// c[i]= k*a[1]+b[i];
cv::scaleAdd(imageA,k,imageB,resultC);
// if (mask[i]) c[i]= a[i]+b[i];
cv::add(imageA,imageB,resultC,mask);
mask必须是单通道的。

void fun_arithmetic(cv::Mat &image1,cv::Mat &image2)
{
    // 出错,图像要求同样的size..
    //cv::add(image2,image1,image1);

    cv::Mat tmp = image1(cv::Rect(10,10,image2.cols,image2.rows));

   // image2.copyTo(tmp);
    // 以下函数会用到 cv::saturate_cast 数值是安全的。
    //   cv::addWeighted(tmp,0.6,image2,0.4,0,tmp); 这个跟下一个重载了的函数效果相同。
    tmp = 0.6*tmp + image2*0.4;
 
}

6. 通道的分离与合并。

split 将图像分离成各个通道  
merge 将几个通道合成图像

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值