sample for Histogram Equalization
От: Denis Россия http://blogs.gotdotnet.ru/personal/Denis
Дата: 28.04.05 09:24
Оценка:
привет всем!
есть совсем глупый вопрос, подскажите сампл простой который иллюстрирует subj. А то читаю книгу, всё здорово написано, но с примерами беда и порой трудно понять смысл не попробовав руками.

Спасибо.
Re: sample for Histogram Equalization
От: Lafkadio Россия  
Дата: 28.04.05 10:38
Оценка: 18 (3)
Здравствуйте, Denis, Вы писали:

D>есть совсем глупый вопрос, подскажите сампл простой который иллюстрирует subj.

Я пользуюсь следующей функцией:
Функция выравнивает гистограмму заданной прямоугольной области изображения. По рассчитанной гистограмме вычисляется дискретная функция распределения, в табличном представлении. Данная функция преобразует яркость изображения таким образом, чтобы гистограмма преобразованного поля была максимально приближена к равномерной. Далее для каждого пикселя изображения, его значение считается индексом в массиве табличного представления функции преобразования, и заменяется на выбранное в ней значение. Алгоритм функции взят из В. Яншин, Г. Калинин "Обработка изображений на языке Си для IBM PC. Алгоритмы и программы", Мир, 1994г. с 88-89.
 // Для простоты считаем что работаем с 8-битным изображением
 // m_ChannelSize- размер изображения
 // m_pActiveChannel - массив пикселей изобржения
 long pHist[256];//Гистограмма исходного изображения

 //очищаем гистограмму
 for (int i=0; i< 255; i++) 
    pHist[i] = 0;

 // Вычисляем гистограмму
 for (i=0; i< m_ChannelSize; i++)
    pHist[m_pActiveChannel[i]]++;

 int  ;
 long pHistNew[256];
 int Derr;
 DWORD Vg, SumDes, SumFct=0;
 BYTE Fns[256];// функция табличного преобразования

 Vg=0;
 for(i=255; i>=0; i--) 
 {
    Vg += pHist[i];
        pHistNew[i]=0;
 }

 //Вычисляем функцию распределения вероятности, апроксимруя ее
 //выражением P(x)=sum H(i),i=0..x где H- массив гистограммы
 for(i=255; i>=0; i--) 
    Vg -= (pHistNew[i] = Vg/(i+1));

 SumDes = pHistNew[0];
 // Вычисляем функцию табличного преобразования
 for (i=0, j=0; j<=255; )
 {
    Derr=SumDes-SumFct;
    if (pHist[j]<= 2*Derr)
    {
        SumFct += pHist[j];
        Fns[j++]=i;
    }
    else
    {
        Fns[j]=i++;
        if (i <= 255) 
                        SumDes += pHistNew[i];
    }
 }

 // Вычисляем границы гистограммы исходного изображения
 for (j=255; pHist[j]==0; j--);
 for (i=0; pHist[i]==0; i++);
 if (j-i > 255)
 {
    Fns[0]=0;
    Fns[r]=255;
 }

 // Вычисляем новое значение каждого пикселя по табличной функции
 for (i=0; i< m_ChannelSize; i++)
    m_pActiveChannel[i]=Fns[m_pActiveChannel[i]];


В книге Crane R., Simplified approach to image processing in C (PH, 1997)(ISBN 0132264161), p.49 приведен другой алгоритм:

/***************************************************************************
 * Func: histogram_equalize                                                *
 *                                                                         *
 * Desc: histogram equalize an input image and write it out                *
 *                                                                         *
 * Params: buffer - pointer to image in memory                             *
 *         number_of_pixels - total number of pixels in image              *
 ***************************************************************************/

void histogram_equalize(image_ptr buffer, unsigned long number_of_pixels)
    {
    unsigned long histogram[256]; /* image histogram */
    unsigned long sum_hist[256];  /* sum of histogram elements */
    float scale_factor;           /* normalized scale factor */
    unsigned long i;              /* index variable */
    unsigned long sum;            /* variable used to increment sum of hist */

    /* clear histogram to 0 */
    for(i=0; i<256; i++)
    histogram[i]=0;

    /* calculate histogram */
    for(i=0; i<number_of_pixels; i++)
    histogram[buffer[i]]++;

    /* calculate normalized sum of hist */
    sum = 0;
    scale_factor = 255.0 / number_of_pixels;
    for(i=0; i<256; i++)
    {
    sum += histogram[i];
    sum_hist[i] = (sum * scale_factor) + 0.5;
    }

    /* transform image using new sum_hist as a LUT */
    for(i=0; i<number_of_pixels; i++)
    buffer[i] = sum_hist[buffer[i]];
    }
Re[2]: sample for Histogram Equalization
От: Denis Россия http://blogs.gotdotnet.ru/personal/Denis
Дата: 28.04.05 11:04
Оценка:
спасибо!!!
Re[2]: sample for Histogram Equalization
От: Reunion  
Дата: 11.07.05 04:50
Оценка:
Здравствуйте, Lafkadio, Вы писали:

L>Я пользуюсь следующей функцией:

L>Функция выравнивает гистограмму заданной прямоугольной области изображения. По рассчитанной гистограмме вычисляется дискретная функция распределения, в табличном представлении. Данная функция преобразует яркость изображения таким образом, чтобы гистограмма преобразованного поля была максимально приближена к равномерной. Далее для каждого пикселя изображения, его значение считается индексом в массиве табличного представления функции преобразования, и заменяется на выбранное в ней значение. Алгоритм функции взят из В. Яншин, Г. Калинин "Обработка изображений на языке Си для IBM PC. Алгоритмы и программы", Мир, 1994г. с 88-89.

Спасибо за этот исходник, но вы не могли бы пояснить подробнее, что откуда берется. (Я только про этот метод, второй везде описывается — с ним просто). Кстати, есть и по коду вопросы:

L>
L> // Для простоты считаем что работаем с 8-битным изображением
L> // m_ChannelSize- размер изображения
L> // m_pActiveChannel - массив пикселей изобржения
L> long pHist[256];//Гистограмма исходного изображения

L> //очищаем гистограмму
L> for (int i=0; i< 255; i++) 
L>    pHist[i] = 0;

L> // Вычисляем гистограмму
L> for (i=0; i< m_ChannelSize; i++)
L>    pHist[m_pActiveChannel[i]]++;

L> int  ;
L> long pHistNew[256];
L> int Derr;
L> DWORD Vg, SumDes, SumFct=0;
L> BYTE Fns[256];// функция табличного преобразования

L> Vg=0;
L> for(i=255; i>=0; i--) 
L> {
L>    Vg += pHist[i];
L>        pHistNew[i]=0;
L> }

L> //Вычисляем функцию распределения вероятности, апроксимруя ее
L> //выражением P(x)=sum H(i),i=0..x где H- массив гистограммы
L> for(i=255; i>=0; i--) 
L>    Vg -= (pHistNew[i] = Vg/(i+1));

L> SumDes = pHistNew[0];
L> // Вычисляем функцию табличного преобразования
L> for (i=0, j=0; j<=255; )
L> {
L>    Derr=SumDes-SumFct;
L>    if (pHist[j]<= 2*Derr)
L>    {
L>        SumFct += pHist[j];
L>        Fns[j++]=i;
L>    }
L>    else
L>    {
L>        Fns[j]=i++;
L>        if (i <= 255) 
L>                        SumDes += pHistNew[i];
L>    }
L> }

L> // Вычисляем границы гистограммы исходного изображения
L> for (j=255; pHist[j]==0; j--);
L> for (i=0; pHist[i]==0; i++);
L> if (j-i > 255)
L> {
L>    Fns[0]=0;
L>    Fns[r]=255;
L> }

Зачем этот кусок, ведь в if мы никогда не попадаем...

L> // Вычисляем новое значение каждого пикселя по табличной функции
L> for (i=0; i< m_ChannelSize; i++)
L>    m_pActiveChannel[i]=Fns[m_pActiveChannel[i]];

L>


[skiped]
Re[3]: sample for Histogram Equalization
От: Lafkadio Россия  
Дата: 11.07.05 10:05
Оценка:
L>> if (j-i > 255)
L>> {
L>> Fns[0]=0;
L>> Fns[r]=255;
L>> }[/b]
R>Зачем этот кусок, ведь в if мы никогда не попадаем...
Согласен, можно убрать. это просто осталось от исходного кода Яншина и Калинина, они не только выравнивали гистограмму но и одновременно масштабировали ее в пределах Umin и Umax. Публикую целиком раздел посвященный выравниванию гистограммы.


Как говорилось выше, необходимо «развязать» между собой диапазон уровней исходного изображения и диапазон уровней, воспроизводимых на экране программами тонового вывода. Для этого мы используем функциональное преобразование уровня.
Для нахождения требуемой функции служит подпрограмма KIPJAR (листинг 2.8). Искомая функция находится посредством сопоставления гистограммы исходного изображения с гистограммой, которую должно иметь преобразованное изображение в идеальном случае. Для получения гистограммы исходного изображения вызывается подпрограмма KIMHIS. Здесь мы несколько забегаем вперед, так как эта подпрограмма рассматривается только в следующей главе (что не мешает нам воспользоваться ей). В качестве желаемой берется равномерная гистограмма; при необходимости можно задать любую другую. Функция преобразования получается из условия пошаговой минимизации отклонения гистограммы преобразованного изображения от требуемой формы. Подпрограмма KIPJAR имеет 6 параметров. Это исходное изображение, его размеры, минимальный и максимальный уровень преобразованного поля и массив, в который помещается (в табличной форме) найденная функция. Подпрограммы KIPIMA и KIPIMD дают примеры использования полученной функции.




void KIPJAR (Image, Ni, Nj, Umin, Umax, Fns)
SHOW Image[];
int Ni, Nj, Umin, Umax;
int Fns;            //Fns[0:MURMAX]
/* Получение таблично заданной функции Fns[]
    преобразующей яркость изображения таким образом, 
    чтобы гистограмма преобразованного поля была
    максимально приближена к равномерной.
    Беспоисковый локально-оптимальный алгоритм.

    Image - исходное изображение
    Ni, Nj - его размеры
    Umin - требуемый минимальный уровень
    Umax - требуемый максимальный уровень
    Fns - сформированная нелинейность

*/
int u, r;
int Hold[MURMAX +1];// для прежней гистограммы
int Hdes[MURMAX +1];// для желаемой гистограммы
int Derr;
unsigned int Vg, SumDes, SumFct=0;

if (Umin<0 || Umin > Umax || Umax > MURMAX)
{
    // Lafkdio. Выдача сообщения об ошибке
    return;
}

KIMHIS(Image, Ni, Nj, Hold); // Получение гистограммы изображения
// Lafkadio. Приводить эту функцию не буду так как эта часть обычно сложностей не вызывает.

Vg=0;
for(u=MURMAX; u >= 0; u--)
{
    Vg+= Hold[u]; 
    Hdes[u]=0;
}
for(u=Umax; u >= Umin; u--)
{
    Vg-= (Hdes[u]=Vg/ (u-Umin+1));
}

SumDes = Hdes[0];
for(u=0, r=0;r <=MURMAX;)
{
    Derr=SumDes-SumFct;
    if (Hold[r]<= 2*Derr)
    {
        SumFct+=Hold[r];
        Fns[r++]=u;
    }
    else
    {
        Fns[r]=u++;
        if(u<Umax)
            SumDes+=Hdes[u];
    }
    }
}

for(r=MURMAX;Hold[r]==0;r--);
for(u=0;Hold[u]==0;u++);

if (r-u>Umax-Umin)
{
    Fns[0]=Umin;
    Fns[r]=Umax;
}
}
Re[4]: sample for Histogram Equalization
От: Reunion  
Дата: 12.07.05 03:54
Оценка:
Здравствуйте, Lafkadio, Вы писали:

[skiped]

Я тут поколдовал над исходником и вот, что получилось:

void CHistogramDlg::Equilize2(CImage *pSrcImg, CImage *pDstImg)
{
    long histogram[256];                // Histogram of the source image

    /**long new_histogram[256];**/        // Desired histogram
    long uniform_level;                    // In here the desired histogram is
                                        // replaced with one uniform level

    byte LUT[256];                        // Table transform function - LUT
    int error;
    unsigned long total, sum_des, sum_fct;

    int w = pSrcImg->GetWidth();        // With od the images
    int h = pSrcImg->GetHeight();        // Height of the images
    // Other variables
    int x, y, c, i, j;
    BYTE *pPix1 = NULL, *pPix2 = NULL;

    // Zero the histogram
    for(c = 0; c < 256; c ++)
        histogram[c] = 0;

    // Calculate the source image histogram
    for(y = 0; y < h; y ++)
        for(x = 0; x < w; x ++){
            pPix1 = pSrcImg->GetPixel(x, y);
            // Calculate intensity
            c = (int)floor(0.299 * (*(pPix1 + 2)) + 0.587 * (*(pPix1 + 1)) + 0.114 * (*pPix1));
            histogram[c] ++;
        }

    total = w * h;
    uniform_level = total / 256;
    /** // Calculate the desired (flat) histogram
    for(i = 0; i < 256; i ++)
        new_histogram[i] = total / 256;**/

    // Calculate table transform function
    sum_des = uniform_level/**new_histogram[0]**/;
    sum_fct = 0;
    for(i = 0, j = 0; j <= 255; ){
        error = sum_des - sum_fct;
        LUT[j] = i;
        if(histogram[j] <= 2 * error){
            sum_fct += histogram[j];
            j ++;
        }
        else{
            i ++;
            if(i <= 255)
                sum_des += uniform_level/**new_histogram[i]**/;
        }
    }

    // Apply
    for(y = 0; y < h; y ++)
        for(x = 0; x < w; x ++){
            pPix1 = pSrcImg->GetPixel(x, y);
            pPix2 = pDstImg->GetPixel(x, y);

            *(pPix2 + 2) = LUT[*(pPix1 + 2)];
            *(pPix2 + 1) = LUT[*(pPix1 + 1)];
            *pPix2 = LUT[*pPix1];
        }
}


Теперь пояснения.
Вот это кусок кода...
Vg=0;
for(i=255; i>=0; i--) 
{
    Vg += pHist[i];
    pHistNew[i]=0;
}

... делает ни что иное, как подсчет количества пикселей и обнуление желаемой гистограммы.

Это...
for(i=255; i>=0; i--) 
    Vg -= (pHistNew[i] = Vg/(i+1));

... равносильно...
for(i=0; i<256; i++) 
    pHistNew[i] = total / 256;

... где total — число пикселей в изображении.
Тогда возникает вопрос, зачем заводить целый массив если все его элементы одинаковы и в дальнейшем не изменяются. Поэтому я заменил его одной переменной.
Код работы с массивом оставил на случай, если придет в голову как можно задать другую (например "более подходящую") гистограмму. Но пока таких мыслей нет...

PS. Кстати, а у тебя есть книга Яншина в электронном виде?
Re[5]: sample for Histogram Equalization
От: Lafkadio Россия  
Дата: 12.07.05 15:25
Оценка:
Здравствуйте, Reunion, Вы писали:
R>PS. Кстати, а у тебя есть книга Яншина в электронном виде?
здесь в течение 14 дней до 19:21 26.07.2005.
Re[6]: sample for Histogram Equalization
От: Reunion  
Дата: 13.07.05 04:17
Оценка:
Здравствуйте, Lafkadio, Вы писали:

L>Здравствуйте, Reunion, Вы писали:

R>>PS. Кстати, а у тебя есть книга Яншина в электронном виде?
L>здесь в течение 14 дней до 19:21 26.07.2005.

Спасибо!
Re[6]: sample for Histogram Equalization
От: Аноним  
Дата: 15.07.05 05:22
Оценка:
Здравствуйте, Lafkadio, Вы писали:

L>Здравствуйте, Reunion, Вы писали:

R>>PS. Кстати, а у тебя есть книга Яншина в электронном виде?
L>здесь в течение 14 дней до 19:21 26.07.2005.

А есть у тебя еще какие-нибудь книги по компьютерной графике? Где ты их берешь? Может сайт какой-нибудь знаешь?
Re[7]: sample for Histogram Equalization
От: Lafkadio Россия  
Дата: 15.07.05 09:38
Оценка:
Здравствуйте, Аноним, Вы писали:
А>А есть у тебя еще какие-нибудь книги по компьютерной графике? Где ты их берешь? Может сайт какой-нибудь знаешь?
Раньше был сайт Kolhoz, где было выложено огромное количство научных книг, по разным направленииям от математики и физики до исскуственного интеллекта и обработки изображения. Но он закрылся или сменил доменное имя. Кое-что я успел закачать. Иногда можно найти что-нибудь на Avax, но там нужно отслеживать, так как публикации очень быстро обновляются. Иногда попадаются хорошие зарубежные книги в html-формате. Например Digital Image Processing. Ming Jiang. Но как показывает практика, прочитать все книжки невозможно, да и не нужно. Большая часть информации повторяется из книги в книгу с небольшими вариациями в материале и подходе к изложению. Лучше искать научные статьи на конкретные темы. Зачастую зарубежные авторы выкладывают свои публикации в открытый доступ.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.