Я думаю, это такой простой вопрос (я пришел с 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, в результате получается только 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 все время! histogramArray [1] = 2; работает отлично. Также histogramArray [(int) image [i] [j]] ++; кажется, что-то рассчитывает, но, как я уже сказал, я думаю, что это неправильно вычисляет.
Я очень ценю любую помощь! Причина, по которой я использовал 2D Array, заключается в том, что он запрашивается. Мне больше нравится 1D версия, потому что она намного проще!
Видите ли, текущая проблема в вашем коде не увеличение значения по сравнению с присвоением ему; это способ, которым вы индексируете свое изображение. То, как вы написали свой 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.
Причину, по которой третий случай не сработает, сложно объяснить просто. Достаточно сказать, что такой двумерный массив не будет неявно распадаться на указатель на указатель, и если это произойдет, это будет бессмысленно. Вопреки тому, что вы могли бы прочитать в некоторых книгах или услышать от некоторых людей, в 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 int
s, а не отдельные байты. Похоже, ваша проблема заключается в том, что значение векторных элементов остается равным нулю, когда вы упрощаете код и увеличиваете только один элемент, и не соответствует значениям, которые должны быть при запуске реального кода. Ну, это может быть признаком числового преобразования. Если количество пикселей в вашем изображении кратно 256 (например, изображение 32×32 или 1024×1024), то естественно, что сумма их числа будет равна 0 mod 256.
Я уже упоминал об этом в своем первоначальном ответе. Если вы читаете мою реализацию histogram
функция, вы видите в подписи, что я объявил мой вектор как vector<unsigned>
и поместил над ним комментарий, в котором говорится, что этот победитель считает пиксели, поэтому его тип данных должен быть подходящим.
Я думаю, я должен был сделать это смелее и яснее! Я надеюсь, что это решит вашу проблему.
Других решений пока нет …