작성일: [[Date(2014-08-08T05:31:05)]] [[TableOfContents]] == 개요 == 어떤 게시판에서 학부생이 이미지 히스토그램을 만드는 질문 글을 올린 걸 봤는데 어렵지 않을 것 같아서 만들어봤다. 우선 생각해본 대로 만들어봤다. 1. 이미지를 비트맵으로 변환한다. 2. 비트맵 데이터를 가져온다. 3. 비트를 읽어 RGB 값을 카운트 한다. 4. 그래프를 찍어 그린다. 처음 RGB 값을 화면에 그릴 때 카운트한 값의 최대를 그래프 높이로 두고 출력했다. 그 결과 히스토그램이 출력되기는 했는데 상용 소프트에서 보여주는 히스토그램과 같지 않았다 ^^Screenshot 1^^ . 상용 소프트의 히스토그램은 Raw한 값이 아닌 것 같았다 ^^Screenshot 2^^ . 모든 그래프가 보기 좋게 출력되는 비율 조정이 필요해 보였다. 생각해 봤는데 출력되는 __최소__ 면적 기준으로 조정하면 되겠다 싶었다. 출력되는 그래프의 최소 면적을 전체 면적의 25%로 스레숄드를 주고 비율을 조절하니 보기 좋아졌다. 즉, 3. RGB 값을 카운트 한다. 3-1. 스케일을 조정한다. <-- 추가 4. 그래프를 찍어 그린다. 과정이 되었다. == Screenshots == attachment:140808_01.png 실제 히스토그램 attachment:140808_04.png 포토샵 히스토그램 attachment:140808_02.png 조정된 비율 attachment:140808_03.png ##attachment:140808_05.png == Code == {{{#!folding PrintHistogram {{{#!gcode void CRGBHistogramDlg::PrintHistogram() { CBitmap bitmap; if (m_hBitMap) { // Set Data bitmap.Attach(m_hBitMap); BITMAP bm_info; bitmap.GetBitmap(&bm_info); int bm_bps = bm_info.bmBitsPixel / 8; int bm_size = bm_info.bmWidth * bm_info.bmHeight * bm_bps; BYTE *p_bit_pattern = new BYTE[bm_size]; bitmap.GetBitmapBits(bm_size, p_bit_pattern); for (int pos = 0; pos < bm_size; pos += bm_bps) { ++m_Red[p_bit_pattern[2 + pos]]; ++m_Green[p_bit_pattern[1 + pos]]; ++m_Blue[p_bit_pattern[pos]]; } free(p_bit_pattern); } // Red DrawGraph(20, 10, m_Red, RGB(255, 0, 0)); // Green DrawGraph(20, 130, m_Green, RGB(0, 255, 0)); // Blue DrawGraph(20, 250, m_Blue, RGB(0, 0, 255)); } }}} }}} {{{#!folding DrawGraph {{{#!gcode void CRGBHistogramDlg::DrawGraph(int x, int y, unsigned int data[], const COLORREF rgb) { CClientDC dc(this); unsigned int width = 257; unsigned int height = 110; unsigned int data_print[256] = {0,}; // Draw Background CPen pen; pen.CreatePen(PS_SOLID, 1, RGB(150,150,150)); CPen *oldPen = dc.SelectObject(&pen); dc.Rectangle(x, y, x + width, y + height); dc.SelectObject(oldPen); // Normalize unsigned int max_n = 0; for (int i = 0; i < 256; ++i) if (data[i] > max_n) max_n = data[i]; double ratio = max_n ? (1.0 * (height - 1) / max_n) : 0.0; // Adjust Scale double adjust = 1.0; double min_threshold = 0.24; // 24% unsigned int min_threshold_cnt = (unsigned int)(height * width * min_threshold); unsigned int cnt = 0; while (1) { cnt = 0; for (int i = 0; i < 256; ++i) cnt += (unsigned int)((data[i] * adjust) * ratio); if (cnt == 0 || cnt > min_threshold_cnt) break; adjust += 0.1; } if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck() == TRUE) adjust = 1.0; // Set data for (int i = 0; i < 256; ++i) data_print[i] = (unsigned int)((data[i] * adjust) * ratio); // Draw Graph CPen penData; penData.CreatePen(PS_SOLID, 1, rgb); oldPen = dc.SelectObject(&penData); for (int i = 0; i < 256; ++i) { if (data_print[i] == 0) continue; dc.MoveTo(x + i, y + height - 2); dc.LineTo(x + i, y + height - (data_print[i] > height ? height : data_print[i]) - 1); } dc.SelectObject(oldPen); } }}} }}} == Binary == attachment:rgb-histogram.zip ---- CategoryApplication