【问题标题】:Add 1 to vector<unsigned char> value - Histogram in C++将 1 添加到向量<unsigned char> 值 - C++ 中的直方图
【发布时间】:2014-05-01 08:32:19
【问题描述】:

我想这是一个很简单的问题(我来自 Java),但我不知道它是如何工作的。

我只想将向量元素加一。这样做的原因是,我想根据图像值计算直方图。但是无论我尝试什么,我都可以完成为向量分配一个值。但不要加一!

这是我的直方图函数:

void histogram(unsigned char** image, int height,
        int width, vector<unsigned char>& histogramArray) {

    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {


//          histogramArray[1] = (int)histogramArray[1] + (int)1;
// add histogram position by one if greylevel occured
            histogramArray[(int)image[i][j]]++;
        }
    }
// display output
    for (int i = 0; i < 256; i++) {
        cout << "Position: " << i << endl;
        cout << "Histogram Value: " << (int)histogramArray[i] << endl;
    }
}

但是无论我尝试在 histogramArray 位置添加 1,它都会导致输出中只有 0。我只能分配具体的值,例如:

histogramArray[1] = 2;

有没有简单易行的方法?我虽然希望在这一点上不需要迭代器,因为我知道我想要增加某些东西的 exakt 索引位置。

编辑: 很抱歉,我的问题应该更准确,谢谢你到目前为止的帮助!上面的代码可以正常工作,但它显示的直方图中的平均值(差异约为 90)与应有的不同。直方图的值也与图形程序中的不同——即使图像值完全相同!这就是为什么我研究了该函数并发现如果我将直方图设置为零然后尝试增加一个元素,没有任何反应!这是上面的注释代码:

for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                histogramArray[1]++;
    // add histogram position by one if greylevel occured
                // histogramArray[(int)image[i][j]]++;
            }
        }

所以位置 1 保持为 0,而不是值 height*width。正因为如此,我认为正确的计算 histogramArray[image[i][j]]++;也不能正常工作。

你对此有什么解释吗?这是我的主要问题,对不起。

为了完整起见,这是我的直方图平均函数:

unsigned char meanHistogram(vector<unsigned char>& histogram) {
    int allOccurences = 0;
    int allValues = 0;
    for (int i = 0; i < 256; i++) {
        allOccurences += histogram[i] * i;
        allValues += histogram[i];
    }
    return (allOccurences / (float) allValues) + 0.5f;
}

我像这样初始化图像:

unsigned char** image= new unsigned char*[width];
for (int i = 0; i < width; i++) {
image[i] = new unsigned char[height];
}

但是初始化代码应该没有任何问题,因为所有其他计算都可以完美运行,并且我能够操纵和保护原始图像。但这是真的,我应该改变宽度和高度——因为我只有方形图像,到目前为止这并不重要。 直方图是这样创建的,然后函数是这样调用的:

vector<unsigned char> histogramArray(256);
histogram(array, adaptedHeight, adaptedWidth, histogramArray);

那么你知道为什么这部分是 histogramArray[1]++;不要增加我的直方图? histogramArray[1] 一直保持为 0!直方图数组[1] = 2;工作正常。还有 histogramArray[(int)image[i][j]]++;似乎计算了一些东西,但正如我所说,我认为它计算错误。 我非常感谢任何帮助!我使用二维数组的原因仅仅是因为它被要求。我也更喜欢 1D 版本,因为它更简单!

【问题讨论】:

  • 问题在于您的数组索引...image[i][j] 不起作用,因为您需要一个指向字符的指针...它应该如何知道数组当它们不在类型中时的尺寸?您可能希望将unsigned char* 然后索引(一次)传递给image[i * width + j],但这取决于ij 中的哪一个在您的数据布局中变化最快。在 C++ 中,编写一个多维数组类是很常见的,它允许例如image(i,j) 表示法来访问您认为是 [i][j] 的元素。
  • 我会添加一行std::cout &lt;&lt; image[i][j] &lt;&lt; std::endl; 以确保您访问的是histogramArray 的正确元素。另外,您是否确定histogramArray 具有所需的元素?您希望在histogramArray 中看到多少项目?如果您事先不知道histogramArray 的大小,map 可能是合适的。
  • 您发布的代码没有任何问题(您有多余的演员表,但它们不会造成问题)。我怀疑调用histogram() 函数的代码中存在问题,您能否证明这一点(包括您传入的参数的全部设置)。
  • 正如@TonyD 所写,问题出在您的image 上。您需要在分配图像的位置发布代码。它从何而来?您是否确实为每个图像分配了height+1 内存? (这可能是这段代码有意义的唯一方法。)你的其余代码都很好;唯一的问题是您分配和索引图像的方式。
  • 正如马特所说,应该没有什么问题。我可以将我的图像用于其他计算并正确修改它并正确打印图像。很抱歉我的问题如此不精确。部分 histogramArray[(int)image[i][j]]++;正在数东西。但我很确定这是错的。因为我的图像值是正确的,但我的输出直方图与图形程序直方图不同。我想如果我尝试 histogramArray[1]++;位置 [1] 仍然为 0!它没有增加。

标签: c++ vector histogram vision


【解决方案1】:

你看,你代码中的当前问题是不是增加一个值而不是分配给它; 这是您索引图像的方式。您编写histogram 函数和图像访问部分的方式非常严格地限制了您需要如何分配图像以使该代码工作。

例如,假设您的直方图函数如您在上面编写的那样,这些图像分配策略都不起作用:(为简洁起见,我使用了char 而不是unsigned char。)

char image [width * height]; // Obvious; "char[]" != "char **"
char * image = new char [width * height]; // "char*" != "char **"
char image [height][width]; // Most surprisingly, this won't work either.

第三种情况不起作用的原因很难简单解释。可以说像这样的 2D 数组不会隐式衰减为指向指针的指针,如果确实如此,那将毫无意义。与您在某些书中读到或从某些人那里听到的相反,在 C/C++ 中,数组和指针不是一回事!

无论如何,为了让你的直方图函数正常工作,你必须像这样分配你的图像:

char** image = new char* [height];
for (int i = 0; i < height; ++i)
    image[i] = new char [width];

现在可以填充图片了,例如:

for (int i = 0; i < height; ++i)
    for (int j = 0; j < width; ++j)
        image[i][j] = rand() % 256; // Or whatever...

在这样分配的图像上,您可以调用直方图函数,它会起作用。完成此图像后,您必须像这样释放它:

for (int i = 0; i < height; ++i)
    delete[] image[i];
delete[] image;

现在,关于分配的内容就足够了。我稍后会回来。

除上述内容外,重要注意图像的迭代顺序。您编写它的方式是在外部遍历列,而内部循环遍历行。我见过的大多数(全部?)图像文件格式和许多(大多数?)图像处理应用程序反过来。我在上面显示的内存分配也假设第一个索引用于行,第二个用于列。我建议你也这样做,除非你有充分的理由不这样做。

无论您为图像选择哪种布局(推荐的行优先或当前的列优先),您都应始终牢记并注意这一问题。

现在,我推荐的分配和访问图像以及计算直方图的方法。

我建议你像这样分配和释放图像:

// Allocate:
char * image = new char [height * width];

// Free:
delete[] image;

就是这样;没有讨厌的(取消)分配循环,每个图像都是一个连续的内存块。当您想访问行 i 和列 j (注意哪个是哪个)时,您可以这样做:

image[i * width + j] = 42;
char x = image[i * width + j];

你会这样计算直方图:

void histogram (
    unsigned char * image, int height, int width,
     // Note that the elements here are pixel-counts, not colors!
    vector<unsigned> & histogram
) {
    // Make sure histogram has enough room; you can do this outside as well.
    if (histogram.size() < 256)
        histogram.resize (256, 0);

    int pixels = height * width;
    for (int i = 0; i < pixels; ++i)
        histogram[image[i]]++;
}

我已经删除了打印代码,无论如何它都不应该存在。请注意,我使用了一个循环来遍历整个图像;这是分配一维数组的另一个优点。此外,对于这个特定功能,您的图像是行优先还是列优先都无关紧要,因为我们通过像素的顺序无关紧要;重要的是我们遍历所有像素,仅此而已。

更新:问题更新后,我认为以上所有讨论都没有实际意义!我相信问题可能出在直方图向量的声明中。它应该是unsigned ints 的向量,而不是单个字节。您的问题似乎是,当您简化代码并仅增加一个元素时,向量元素的值似乎保持为零,并且与运行实际代码时所需的值不同。好吧,这可能是数字环绕的症状。如果图像中的像素数是 256 的倍数(例如 32x32 或 1024x1024 图像),那么它们的数量之和自然会是 0 mod 256。

我已经在我的原始答案中提到了这一点。如果您阅读了我对histogram 函数的实现,您会在签名中看到我已将我的向量声明为vector&lt;unsigned&gt; 并在其上方添加了一条注释,说明此胜利者计算像素,因此它的数据类型应该是合适的。

我想我应该让它更大胆更清晰!我希望这能解决您的问题。

【讨论】:

  • 这篇文章太棒了。你真的把所有东西都包得很好。但不幸的是,我不得不说,我按照你的建议做了一切。我正是以这种方式初始化了图像。我只是搞砸了宽度和高度初始化,因为我只有方形图像并且没有花任何注意力(谢谢你的提示!)。不幸的是,我还必须使用 2D 数组。我在上面编辑了我的问题。也许你可以看看?我的 histogramArray[(int)image[i][j]]++;正在工作,但如果我只是尝试 histogramArray[1]++;这一立场没有改变。它保持为 0。
  • 这很重要,因为我调查了我的直方图均值函数,发现它与图像的正常均值函数不同。但是我的图像值是正确的,所以我发现我的直方图与图形程序有很大不同。我开始研究递增部分,发现它在简单示例中不起作用。这就是为什么现在相信 histogramArray[(int)image[i][j]]++;没有适当增加。也许你可以看看我上面的代码。但是非常感谢你的帖子,太棒了。也许它可以帮助其他谷歌员工!
  • @ManWithConcern:我在答案中添加了“更新”部分。告诉我,你的图片尺寸是 256 的倍数吗?!
  • 信不信由你,我在一分钟前遇到了这个错误,想在这里报告我的愚蠢。但是你快了一个小时:D!这就是问题所在!!!
  • 我不知道为什么我这么愚蠢还用无符号字符初始化直方图。当然,我需要更多的空间。我的图像是 512x512。这个问题太令人困惑和分心了,因为我总是得到 0 来表示递增。但你的回答完全有道理。 512*512 mod 256 正好是 0 xD。非常感谢您的出色帮助!答案已接受;D.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-30
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多