2015-06-20 128 views
0

我想玩一些OpenCV,并想出了一个有趣的小场景工作。 (x,y),(x + 1,y)(x,y + 1)和(x + 1,y)的颜色值相加, y + 1))并将结果除以4得到平均颜色值。然后,我处理的下一组像素是(x + 2,y + 2),它有3个相邻像素。有效的方式访问opencv Mat元素

然后,我也希望能够做一个类似的事情,但与9像素(与选定的坐标作为中心工作)。

最初我从高斯模糊类型掩模开始,但这不是我想要的结果。从这些计算中,我只想得到1个像素值。所以输出图像将是1/4或1/9的大小。所以现在我已经得到了它的工作,我已经从字面上写出来的计算在for循环:

for (int i = 1; i < myImage.rows -1; i++) 
{ 
    b = 0; 
    for (int k = 1; k < myImage.cols -1; k++) 
    { 
     //9 pixel radius 
     Result.at<Vec3b>(a, b)[1] = (myImage.at<Vec3b>(i-1, k-1)[1]+myImage.at<Vec3b>(i-1, k)[1]+myImage.at<Vec3b>(i+1, k)[1] + myImage.at<Vec3b>(i, k)[1]+myImage.at<Vec3b>(i, k-1)[1]+myImage.at<Vec3b>(i, k+1)[1] + myImage.at<Vec3b>(i + 1, k+1)[1] + myImage.at<Vec3b>(i-1, k + 1)[1] + myImage.at<Vec3b>(i + 1, k - 1)[1])/9; 
     Result.at<Vec3b>(a, b)[2] = (myImage.at<Vec3b>(i-1, k-1)[2]+myImage.at<Vec3b>(i-1, k)[2]+myImage.at<Vec3b>(i+1, k)[2] + myImage.at<Vec3b>(i, k)[2]+myImage.at<Vec3b>(i, k-1)[2]+myImage.at<Vec3b>(i, k+1)[2] + myImage.at<Vec3b>(i + 1, k+1)[2] + myImage.at<Vec3b>(i-1, k + 1)[2] + myImage.at<Vec3b>(i + 1, k - 1)[2])/9; 
     Result.at<Vec3b>(a, b)[0] = (myImage.at<Vec3b>(i-1, k-1)[0]+myImage.at<Vec3b>(i-1, k)[0]+myImage.at<Vec3b>(i+1, k)[0] + myImage.at<Vec3b>(i, k)[0]+myImage.at<Vec3b>(i, k-1)[0]+myImage.at<Vec3b>(i, k+1)[0] + myImage.at<Vec3b>(i + 1, k+1)[0] + myImage.at<Vec3b>(i-1, k + 1)[0] + myImage.at<Vec3b>(i + 1, k - 1)[0])/9; 

     //4 pixel radius 
     //  Result.at<Vec3b>(a, b)[1] = (myImage.at<Vec3b>(i, k)[1] + myImage.at<Vec3b>(i + 1, k)[1] + myImage.at<Vec3b>(i, k + 1)[1] + myImage.at<Vec3b>(i, k - 1)[1] + myImage.at<Vec3b>(i - 1, k)[1])/5; 
     //  Result.at<Vec3b>(a, b)[2] = (myImage.at<Vec3b>(i, k)[2] + myImage.at<Vec3b>(i + 1, k)[2] + myImage.at<Vec3b>(i, k + 1)[2] + myImage.at<Vec3b>(i, k - 1)[2] + myImage.at<Vec3b>(i - 1, k)[2])/5; 
     //  Result.at<Vec3b>(a, b)[0] = (myImage.at<Vec3b>(i, k)[0] + myImage.at<Vec3b>(i + 1, k)[0] + myImage.at<Vec3b>(i, k + 1)[0] + myImage.at<Vec3b>(i, k - 1)[0] + myImage.at<Vec3b>(i - 1, k)[0])/5; 
     b++; 
    } 
    a++; 
} 

显然,这是可以设置被称为两个选项不同的功能,但我我只是想知道是否有更高效的方法来实现这一点,这会让掩码的大小发生改变。

感谢您的帮助!

+1

这听起来像你只是谈论与线性插值调整图像大小。 – beaker

+1

您是否打算用opencv实现这种最高效的方式,或者您想学习如何使用opencv进行高效的像素访问? – bendervader

+0

我的意图主要是找到一种更容易的方法来改变用于创建输出的像素的数量,而不仅仅是将其全部写出来,这与opencv相关。它能很好地使用输入算法。而不仅仅是一长串手写代码来完成一组不同的输入。 – FreakShow

回答

0

我假设你想要做的这一切,没有内置函数(如resizemean,或filter2d),只是想用at直接处理图像。还有可以进一步的优化,但这是对原始代码的合理和可理解的改进。

此外,应该指出的是,我忽略任何额外的行/列时,图像大小不是由比例因子整除。如果你想要不同的东西,你需要指定预期的行为。

我要做的第一件事就是改变你认为的目标像素。假设你有一个3x3的邻里,象这样:

1 2 3 
4 5 6 
7 8 9 

我们将采取所有这些像素的平均值无论如何,所以无论我们称之为像素5目标或像素1,使生成的映像没有什么区别。我将调用像素1的目标,因为它使数学更清晰。

1像素将永远是比例因子整除坐标。如果比例因子是2,那么坐标1将始终均匀。其次,不是在原始图像尺寸上循环,这实际上导致重复计算Result中的相同像素,我将循环遍历Result的尺寸并找出原始图像中的哪些像素有助于结果中的每个像素。

因此,要找到结果图像中对应于像素(x, y)的原始图像中的邻域,我们只需要查找该邻域的像素1。由于它的比例因子的倍数,它只是

(x * scaleFactor, y * scaleFactor) 

最后,我们需要两个嵌套循环在scaleFactor x scaleFactor窗口中添加循环。这是避免必须输出这些长计算的部分。

在上面的3×3示例中,例如,在(x, y)附近像素9将是:

(x * scaleFactor + 2, y * scaleFactor + 2) 

我也直接做平均值计算在载体中而不是单独做每个信道。这意味着我们的结果将溢出uchar,所以我使用Vec3i并在分割后将其重新设置为Vec3b。这是您应该考虑使用内置函数mean来计算窗口平均值的一个地方,因为它将消除这些新循环的需要。

所以,如果我们的原始图像是myImage,我们有:

int scaleFactor = 3; 

Mat Result(myImage.rows/scaleFactor, myImage.rows/scaleFactor, 
      myImage.type(), Scalar::all(0)); 

for (int i = 0; i < Result.rows; i++) 
{ 
    for (int k = 0; k < Result.cols; k++) 
    { 
     // make sum an int vector so it can hold 
     // value = scaleFactor x scaleFactor x 255 
     Vec3i areaSum = Vec3i(0,0,0); 
     for (int m = 0; m < scaleFactor; m++) 
     { 
      for (int n = 0; n < scaleFactor; n++) 
      { 
       areaSum += myImage.at<Vec3b>(i*scaleFactor+m, k*scaleFactor+n); 
      } 
     } 

     Result.at<Vec3b>(i,k) = Vec3b(areaSum/(scaleFactor*scaleFactor)); 
    } 
} 

这里有几个样本...

原文:

enter image description here

比例因子= 2 :

enter image description here

比例因子= 3:

enter image description here

比例因子= 5:

enter image description here