영상 처리 프로그래밍 - 히스토그램 처리

이효정·2022년 9월 19일
post-thumbnail

히스토그램 처리
입력되는 화소의 히스토그램을 분석하여 처리하는 알고리즘
ex) 스트래칭, 엔드-인, 평활화

디지털 히스토그램

관찰한 데이터의 특징을 한눈에 알아볼 수 있도록 데이터를 막대그래프 모양으로 나타낸 것

<히스토 스트래칭>

-낮은 명암 대비를 가진 영상의 화질을 향상
-특정 부분이나 가운데에 집중된 히스토그램을 모든 영역으로 확장
이미 히스토그램이 고르게 분포되어 있으면 스트레칭을 적용해도 큰 품질 향상이 없음

function stretchImage() { // 히스토그램 스트래칭 알고리즘
            // (중요!) 출력 이미지의 크기가 결정 ---> 알고리즘에 의존...
            outH = inH;
            outW = inW;
            // 출력 영상의 2차원 메모리 할당
            outImage = new Array(outH);
            for(let i=0; i<outH; i++)
                outImage[i] = new Array(outW);
            // **** 진짜 영상처리 알고리즘 *****
            // 공식 : out = (in-LOW) / (HIGH - LOW) * 255.0
            // let LOW = 255, HIGH =0;   // 255보다는 작겠지, 0보다 작은게 없으면 버그
            let LOW = inImage[0][0], HIGH = inImage[0][0];
            for (let i=0; i<inH; i++) 
                for (let k=0; k<inW; k++) {
                    if (LOW > inImage[i][k])
                        LOW = inImage[i][k];
                    if (HIGH < inImage[i][k])
                        HIGH = inImage[i][k];
                }

            for (let i=0; i<inH; i++) {
                for (let k=0; k<inW; k++) {
                    let out =  (inImage[i][k] - LOW) / (HIGH - LOW) * 255.0;
                    if (out < 0.0)
                        out = 0;
                    else if (out > 255.0)
                        out = 255;
                    else 
                        out = parseInt(out);

                    outImage[i][k] = out;
                }
            }
            // ******************************
            displayImage();
        }

<엔드-인>

-일정한 양의 화소를 흰색(0)이나 검정색(255)으로 지정하여 히스토그램의 분포를 좀더 균일하게 만들어 준다

function endInImage() { // 엔드-인 탐색 알고리즘
            // (중요!) 출력 이미지의 크기가 결정 ---> 알고리즘에 의존...
            outH = inH;
            outW = inW;
            // 출력 영상의 2차원 메모리 할당
            outImage = new Array(outH);
            for(let i=0; i<outH; i++)
                outImage[i] = new Array(outW);
            // **** 진짜 영상처리 알고리즘 *****
            // 공식 : out = (in-LOW) / (HIGH - LOW) * 255.0
            // let LOW = 255, HIGH =0;   // 255보다는 작겠지, 0보다 작은게 없으면 버그
            let LOW = inImage[0][0], HIGH = inImage[0][0];
            for (let i=0; i<inH; i++) 
                for (let k=0; k<inW; k++) {
                    if (LOW > inImage[i][k])
                        LOW = inImage[i][k];
                    if (HIGH < inImage[i][k])
                        HIGH = inImage[i][k];
                }

            LOW += 50;
            HIGH -= 50;

            for (let i=0; i<inH; i++) {
                for (let k=0; k<inW; k++) {
                    let out =  (inImage[i][k] - LOW) / (HIGH - LOW) * 255.0;
                    if (out < 0.0)
                        out = 0;
                    else if (out > 255.0)
                        out = 255;
                    else 
                        out = parseInt(out);

                    outImage[i][k] = out;
                }
            }
            // ******************************
            displayImage();
        }

<평활화>

-입력 이미지를 출력 이미지에 저장할 때 출력 이미지에 누적 히스토그램을 정규화 하여 픽셀의 분포를 균일하게 조정
-각 명암의 빈도는 변경하지 않음

  1. 입력 영상의 빈도수 히스토그램 생성
// 1단계 : 히스토그램 생성
			histo[inImage[i][k]] ++;

  1. 각 명암 값 i에서 0~i까지의 누적 빈도 수를 계산
 // 2단계 : 누적히스토그램 생성
 for (let i=0; i<256; i++) {
                sumValue += histo[i];
                sumHisto[i] = sumValue;
            }

  1. 2단계에서 구한 누적 빈도 수를 정규화
 for(let i=0; i<256; i++) {
                let normal = sumHisto[i] * (1.0 / (inH * inW)) * 255.0;
                normalHisto[i] = normal;

function equalizeImage() { // 히스토그램 평활화 알고리즘
            // 어둡게 찍힌 영상에 효과적
            // (중요!) 출력 이미지의 크기가 결정 ---> 알고리즘에 의존...
            outH = inH;
            outW = inW;
            // 출력 영상의 2차원 메모리 할당
            outImage = new Array(outH);
            for(let i=0; i<outH; i++)
                outImage[i] = new Array(outW);
            // **** 진짜 영상처리 알고리즘 *****
            // 1단계 : 히스토그램 생성
            let histo = new Array(256);
            // 초기화
            for(let i=0; i<256; i++)
                histo[i] =0;
            // 카운트
            for (let i=0; i<inH; i++) 
                for (let k=0; k<inW; k++) 
                    histo[inImage[i][k]] ++;
            // 2단계 : 누적히스토그램 생성
            let sumHisto = new Array(256);
            // 초기화
            for(let i=0; i<256; i++)
                sumHisto[i] =0;
            // 계산
            let sumValue = 0;
            for (let i=0; i<256; i++) {
                sumValue += histo[i];
                sumHisto[i] = sumValue;
            }
            // 3단계 : 정규화된 누적 히스토그램 생성
            // 공식 : normal = sum * (1.0 / (inH*inW) ) * 255;
            let normalHisto = new Array(256);
            // 초기화
            for(let i=0; i<256; i++)
                normalHisto[i] =0.0;
            // 계산
            for(let i=0; i<256; i++) {
                let normal = sumHisto[i] * (1.0 / (inH * inW)) * 255.0;
                normalHisto[i] = normal;
            }
            // 영상 처리
            for (let i=0; i<inH; i++) {
                for (let k=0; k<inW; k++) {
                    outImage[i][k] = parseInt(normalHisto[inImage[i][k]]);
                }
            }
            // ******************************
            displayImage();
        }

0개의 댓글