我怎么能像素化1d数组

时间:2014-12-15 00:46:13

标签: c++ arrays image image-processing

我想像素化存储在1d数组中的图像,虽然我不知道该怎么做,但这是我到目前为止所得到的... 为了测试目的,像素化的值目前为3。 目前它只是在图像的左三分之一处创建一段随机彩色像素,如果我增加像素化的值,随机彩色像素的数量减少,反之亦然,那么我做错了什么?

我已经实现了旋转,读取图像和保存新图像这只是一个我需要帮助的单独功能。

picture pixelate( const std::string& file_name, picture& tempImage, int& pixelation /* TODO: OTHER PARAMETERS HERE */)
{
picture pixelated = tempImage;
RGB tempPixel;
tempPixel.r = 0;
tempPixel.g = 0;
tempPixel.b = 0;
int counter = 0;
int numtimesrun = 0;

    for (int x = 1; x<tempImage.width; x+=pixelation)
    {
        for (int y = 1; y<tempImage.height; y+=pixelation)
        {
            //RGB tempcol;
            //tempcol for pixelate
            for (int i = 1; i<pixelation; i++)
            {
                for (int j = 1; j<pixelation; j++)
                {
                    tempPixel.r +=tempImage.pixel[counter+pixelation*numtimesrun].colour.r;
                    tempPixel.g +=tempImage.pixel[counter+pixelation*numtimesrun].colour.g;
                    tempPixel.b +=tempImage.pixel[counter+pixelation*numtimesrun].colour.b;
                    counter++;
                    //read colour
                }

            }
            for (int k = 1; k<pixelation; k++)
            {
                for (int l = 1; l<pixelation; l++)
                {
                     pixelated.pixel[numtimesrun].colour.r = tempPixel.r/pixelation;
                     pixelated.pixel[numtimesrun].colour.g = tempPixel.g/pixelation;
                     pixelated.pixel[numtimesrun].colour.b = tempPixel.b/pixelation;
                    //set colour
                }

            }
            counter = 0;
            numtimesrun++;
        }
        cout << x << endl;

    }
    cout << "Image successfully pixelated." << endl;
return pixelated;
}

3 个答案:

答案 0 :(得分:1)

我不太确定你真正想用你的代码做什么,但我可以看到一些问题。

首先,您使用for()循环,其变量从1开始。这当然是错的。 C / C ++中的数组从0开始。

我能看到的另一个主要问题是pixelation参数。您使用它来增加xy,而不知道(至少在该函数中)它是widthheight的倍数。如果没有,你肯定会在右边缘和底部<<>缺少像素(当然,哪些边缘取决于方向)。同样,这在很大程度上取决于你想要实现的目标。

同样,ij循环从counternumtimesrun定义的位置开始,这意味着您要点击的最后一行不是{{1} }或tempImage.width。有了这个,你很可能会有很多溢出。实际上,这也可以解释你在边缘看到的问题。 (见下面的更新)

另一个潜在的问题是,如果没有看到结构声明,就无法确定,但使用tempImage.height的这个总和可能会溢出。如果RGB组件定义为tempPixel.c += <value>(相当常见),那么您将明确地获得溢出。因此,如果这是事实,你的平均金额就会被打破。如果该结构使用浮动,那么你就是好的。

另请注意,您的平均值是错误的。您正在为unsigned char x pixelation添加源数据,并且您的平均值计算为pixalation。所以你得到的总数是sum / pixelation倍。您可能想要pixalation

sum / (pixelation * pixelation)i的第一个循环计算总和。数学肯定是错的。似乎j表达式将在第二行开始读取。但是,您正在阅读counter + pixelation * numtimesrun值。话虽这么说,它可能是你想要做的(即移动平均线),在这种情况下它可以优化,但我现在就把它留下来。


更新

如果我理解你在做什么,表示就像过滤器一样。有一张3x3的照片:

i * j

左边是您正在阅读的内容。这意味着源需要至少3x3。我在右边显示的是结果。我们可以看到,结果需要是1x1。从我在您的代码中看到的内容,您根本不会考虑到这一点。 (变化的字符代表不同的权重,在你的情况下,所有权重都是1.0)。

您有两种方法可以解决这个问题:

  1. 生成的图片的大小为.+. * +*+ => .+. width - pixelation * 2 + 1;在这种情况下,您保留一个结果而不关心 edge ...
  2. 您重写代码以处理边缘。这意味着您使用较少的源数据来计算生成的。另一种方法是计算边缘情况并将其保存在几个输出像素中(即复制边缘上的像素)。

  3. 更新2

    嗯...再次查看你的代码,似乎你计算3x3的平均值并将其保存在3x3中:

    height - pixelation * 2 + 1

    然后问题就不同了。 .+. *** +*+ => *** .+. *** 错了。在numtimesrunk循环中,您可以将像素l保存在SAME像素中,并且每次前进一次......所以您正在执行我在第一次更新时所显示的内容,但是看起来你正试图做我第二次更新中显示的内容。

    pixelation * pixelation每次增加numtimesrun

    pixelation

    但是,这还不足以修复您的numtimesrun += pixelation; k循环。在那里你可能需要计算正确的目的地。也许这样的事情(也需要在循环之前重置计数器):

    l

    然而,我无法确定你要做什么,所以我不知道你为什么要复制相同的像素counter = 0; ... for loops ... pixelated.pixel[counter+pixelation*numtimesrun].colour.r = ...; ... (take care of g and b) ++counter; 次。但这解释了为什么你只得到图像左侧(或顶部)的数据(很大程度上取决于方向,一方面肯定。如果那是1/3 rd 那么{{1}可能是3。)

    警告:如果您正确实施了保存,如果您不处理前面提到的溢出,您将会遇到崩溃。


    更新3

    正如Mark在下面的评论中所解释的那样,你有一个代表2D图像的数组。在这种情况下,您的pixelation x pixelation变量完全错误,因为这是100%线性,而2d图像则不是。第二行距离pixelation更远。此时,您读取左上角的前3个像素,然后读取相同的下3个像素,最后接下来的3个像素仍在同一行上。当然,可能是你的图像被定义了,这些像素真的是一个接一个,尽管它不太可能...

    Mark的答案很简洁,为您提供访问正确像素所需的信息。但是,您仍会受到溢出的影响,可能还有counterwidth参数不是width的倍数......

答案 1 :(得分:0)

我没有做很多C ++,但这是我为Processing编写的像素化函数。它需要您想要创建的像素的宽度/高度的参数。

void pixelateImage(int pxSize) {

  // use ratio of height/width...
  float ratio;
  if (width < height) {
    ratio = height/width;
  }
  else {
    ratio = width/height;
  }

  // ... to set pixel height
  int pxH = int(pxSize * ratio);

  noStroke();
  for (int x=0; x<width; x+=pxSize) {
    for (int y=0; y<height; y+=pxH) {
      fill(p.get(x, y));
      rect(x, y, pxSize, pxH);
    }
  }
}

如果没有内置的rect()函数,您必须使用另外两个for循环逐个像素地写入:

for (int px=0; px<pxSize; px++) {
  for (int py=0; py<pxH; py++) {
    pixelated.pixel[py * tempImage.width + px].colour.r = tempPixel.r;
    pixelated.pixel[py * tempImage.width + px].colour.g = tempPixel.g;
    pixelated.pixel[py * tempImage.width + px].colour.b = tempPixel.b;
  }
}

答案 2 :(得分:0)

通常,当访问存储在1D缓冲区中的图像时,图像的每一行将作为连续像素存储,下一行将紧随其后。解决这种缓冲区的方法是:

image[y*width+x]

为了您的目的,您希望两个内部循环生成从像素化方块的顶部和左侧到右下角的坐标。