3-6. CORE – Histogram

이미지에 있어서 히스토그램은 무엇인가? 보통 히스토그램을 보면 X,Y 축 형태의 막대 그래프 형태를 가지고 있음을 알 수 있다.

이미지에서 히스토그램 그래프의 X 축은 Depth 즉 CV_8UC1 이라고 하면 0 ~ 255이 될 것이고, Y 축은 각 Depth 의 빈도가 될 것이다.

만약 CV_8UC4 라고 하면? 히스토그램 그래프가 4개가 나올 것이고 각각의 그래프는 위의 싱글채널 그래프와 동일한 형태로 표현될 것이다.

그럼 Android 기반의 OpenCV 에서 Histogram 을 다루는 방법을 알아보자. 아래는 OPENCV 샘플에 포함된 소스코드로

RED , Green, Blue, 색상, 명도 별 히스토그램을 화면에 출력하는 예제이다.

(1) 히스토그램 이미지를 담기 위한 메트릭스를 생성한다.

mRgba = inputFrame.rgba();

if ((mSizeRgba == null) || (mRgba.cols() != mSizeRgba.width) || (mRgba.height() != mSizeRgba.height))
{
//히스토그램 출력 이미지 편집을 위한 메트릭스 생성
CreateAuxiliaryMats();
}

//히스토그램 막대의 폭을 정의한다.
int thikness = (int) (mSizeRgba.width / (mHistSizeNum + 10) / 5);

if(thikness > 5)
{
thikness = 5;
}

int offset = (int) ((mSizeRgba.width – (5*mHistSizeNum + 4*10)*thikness)/2);

(2) 카메라 이미지의 정보로 RGB 에 해당하는 히스토그램을 생성한다.
// RED 에 대한 히스토그랩, GREEN에 대한 히스토그램, BLUE 에 대한 히스토그램을 그린다.
for(int c=0; c<3; c++)
{

//mRgba : 원본 이미지, mChannels : RGB 중 원하는 채널 선택 , 출력값 : mMat0, mHist, mHistSize, mRanges
Imgproc.calcHist(Arrays.asList(mRgba), mChannels[c], mMat0, mHist, mHistSize, mRanges);
Core.normalize(mHist, mHist, mSizeRgba.height/2, 0, Core.NORM_INF);
mHist.get(0, 0, mBuff);
for(int h=0; h<mHistSizeNum; h++) {
mP1.x = mP2.x = offset + (c * (mHistSizeNum + 10) + h) * thikness;
mP1.y = mSizeRgba.height-1;
mP2.y = mP1.y – 2 – (int)mBuff[h];
Core.line(mRgba, mP1, mP2, mColorsRGB[c], thikness);
}
}

// RGB를 HSV [색상(H), 채도(S), 명도(V)] 로 변경하고 명도값을 추출하여 히스토그램으로 표현한다.
Imgproc.cvtColor(mRgba, mIntermediateMat, Imgproc.COLOR_RGB2HSV_FULL);
// Value
Imgproc.calcHist(Arrays.asList(mIntermediateMat), mChannels[2], mMat0, mHist, mHistSize, mRanges);
Core.normalize(mHist, mHist, mSizeRgba.height/2, 0, Core.NORM_INF);
mHist.get(0, 0, mBuff);
for(int h=0; h<mHistSizeNum; h++)
{
mP1.x = mP2.x = offset + (3 * (mHistSizeNum + 10) + h) * thikness;
mP1.y = mSizeRgba.height-1;
mP2.y = mP1.y – 2 – (int)mBuff[h];
Core.line(mRgba, mP1, mP2, mWhilte, thikness);
}

// RGB를 HSV [색상(H), 채도(S), 명도(V)] 로 변경하고 색상 값을 추출하여 표현한다.
Imgproc.calcHist(Arrays.asList(mIntermediateMat), mChannels[0], mMat0, mHist, mHistSize, mRanges);
Core.normalize(mHist, mHist, mSizeRgba.height/2, 0, Core.NORM_INF);
mHist.get(0, 0, mBuff);
for(int h=0; h<mHistSizeNum; h++)
{
mP1.x = mP2.x = offset + (4 * (mHistSizeNum + 10) + h) * thikness;
mP1.y = mSizeRgba.height-1;
mP2.y = mP1.y – 2 – (int)mBuff[h];
Core.line(mRgba, mP1, mP2, mColorsHue[h], thikness);
}