전역 변수
unsigned char ** m_InputImageR = NULL; unsigned char ** m_InputImageG = NULL; unsigned char ** m_InputImageB = NULL; unsigned char ** m_OutputImageR = NULL; unsigned char ** m_OutputImageG = NULL; unsigned char ** m_OutputImageB = NULL; int m_height; int m_width; int m_Re_height; int m_Re_width; int m_old_height; int m_old_width; int m_old_Re_height; int m_old_Re_width;
2차원 동적 배열 할당
unsigned char** malloc2D(int h, int w) { // TODO: 여기에 구현 코드 추가. unsigned char** p; p = (unsigned char**)malloc(h * sizeof(unsigned char*)); for (int i = 0; i < h; i++) p[i] = (unsigned char*)malloc(w * sizeof(unsigned char)); return p; }
입력 이미지 초기화
void freeInputImage(int h) { // TODO: 여기에 구현 코드 추가. if (m_InputImageR != NULL) { for (int i = 0; i < h; i++) free(m_InputImageR[i]); free(m_InputImageR); } m_InputImageR = NULL; if (m_InputImageG != NULL) { for (int i = 0; i < h; i++) free(m_InputImageG[i]); free(m_InputImageG); } m_InputImageG = NULL; if (m_InputImageB != NULL) { for (int i = 0; i < h; i++) free(m_InputImageB[i]); free(m_InputImageB); } m_InputImageB = NULL; }
출력 이미지 초기화
void freeOutputImage(int h) { // TODO: 여기에 구현 코드 추가. if (m_OutputImageR != NULL) { for (int i = 0; i < h; i++) free(m_OutputImageR[i]); free(m_OutputImageR); } m_OutputImageR = NULL; if (m_OutputImageG != NULL) { for (int i = 0; i < h; i++) free(m_OutputImageG[i]); free(m_OutputImageG); } m_OutputImageG = NULL; if (m_OutputImageB != NULL) { for (int i = 0; i < h; i++) free(m_OutputImageB[i]); free(m_OutputImageB); } m_OutputImageB = NULL; }
이미지 오픈(on MFC)
BOOL CMFCApplication1Doc::OnOpenDocument(LPCTSTR lpszPathName) { if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; // TODO: 여기에 특수화된 작성 코드를 추가합니다. // Color 이미지 처리 클래스 CImage m_bitmap; m_bitmap.Load(lpszPathName); // 기존 메모리 해제 freeInputImage(m_old_height); // 중요! 입력 영상 크기 결정 m_height = m_bitmap.GetHeight(); m_width = m_bitmap.GetWidth(); m_old_height = m_height; m_old_width = m_width; // 메모리 할당 m_InputImageR = malloc2D(m_height, m_width); m_InputImageG = malloc2D(m_height, m_width); m_InputImageB = malloc2D(m_height, m_width); // 칼라 이미지 --> 메모리 COLORREF pixel; for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) { pixel = m_bitmap.GetPixel(i, k); m_InputImageR[k][i] = (unsigned char)GetRValue(pixel); m_InputImageG[k][i] = (unsigned char)GetGValue(pixel); m_InputImageB[k][i] = (unsigned char)GetBValue(pixel); } return TRUE; }
종료 시(on MFC)
void OnCloseDocument() { // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다. freeInputImage(m_height); freeOutputImage(m_Re_height); CDocument::OnCloseDocument(); }
동일 영상 알고리즘
void OnEqualColor() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { m_OutputImageR[i][k] = m_InputImageR[i][k]; m_OutputImageG[i][k] = m_InputImageG[i][k]; m_OutputImageB[i][k] = m_InputImageB[i][k]; } } }
반전연산알고리즘
void OnNegativeImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { m_OutputImageR[i][k] = 255 - m_InputImageR[i][k]; m_OutputImageG[i][k] = 255 - m_InputImageG[i][k]; m_OutputImageB[i][k] = 255 - m_InputImageB[i][k]; } } }
더하기연산 알고리즘
void OnAddImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int s = dlg.m_value; int aR, aG, aB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { aR = s + m_InputImageR[i][k]; aG = s + m_InputImageG[i][k]; aB = s + m_InputImageB[i][k]; if (aR > 255) aR = 255; else if (aR < 0) aR = 0; if (aG > 255) aG = 255; else if (aG < 0) aG = 0; if (aB > 255) aB = 255; else if (aB < 0) aB = 0; m_OutputImageR[i][k] = aR; m_OutputImageG[i][k] = aG; m_OutputImageB[i][k] = aB; } } }
빼기연산 알고리즘
void OnSubImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int s = dlg.m_value; int aR, aG, aB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { aR = s - m_InputImageR[i][k]; aG = s - m_InputImageG[i][k]; aB = s - m_InputImageB[i][k]; if (aR > 255) aR = 255; else if (aR < 0) aR = 0; if (aG > 255) aG = 255; else if (aG < 0) aG = 0; if (aB > 255) aB = 255; else if (aB < 0) aB = 0; m_OutputImageR[i][k] = aR; m_OutputImageG[i][k] = aG; m_OutputImageB[i][k] = aB; } } }
곱하기 연산 알고리즘
void OnMulImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int s = dlg.m_value; int aR, aG, aB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { aR = s * m_InputImageR[i][k]; aG = s * m_InputImageG[i][k]; aB = s * m_InputImageB[i][k]; if (aR > 255) aR = 255; else if (aR < 0) aR = 0; if (aG > 255) aG = 255; else if (aG < 0) aG = 0; if (aB > 255) aB = 255; else if (aB < 0) aB = 0; m_OutputImageR[i][k] = aR; m_OutputImageG[i][k] = aG; m_OutputImageB[i][k] = aB; } } }
나누기 연산 알고리즘
void OnDivImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int s = dlg.m_value; int aR, aG, aB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { aR = s / m_InputImageR[i][k]; aG = s / m_InputImageG[i][k]; aB = s / m_InputImageB[i][k]; if (aR > 255) aR = 255; else if (aR < 0) aR = 0; if (aG > 255) aG = 255; else if (aG < 0) aG = 0; if (aB > 255) aB = 255; else if (aB < 0) aB = 0; m_OutputImageR[i][k] = aR; m_OutputImageG[i][k] = aG; m_OutputImageB[i][k] = aB; } } }
감마 연산 알고리즘
void OnGammaImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** double s = dlg.m_value; double aR, aG, aB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { aR = pow(m_InputImageR[i][k], 1 / s); aG = pow(m_InputImageG[i][k], 1 / s); aB = pow(m_InputImageB[i][k], 1 / s); if (aR > 255) aR = 255; else if (aR < 0) aR = 0; if (aG > 255) aG = 255; else if (aG < 0) aG = 0; if (aB > 255) aB = 255; else if (aB < 0) aB = 0; else m_OutputImageR[i][k] = aR; else m_OutputImageG[i][k] = aG; else m_OutputImageB[i][k] = aB; } } }
명암 대비 스트레치(늘리기) 알고리즘
void OnStretchImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** double s = dlg.m_value; double aR, aG, aB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { aR = ((m_InputImageR[i][k] - 128) * s) + 128; aG = ((m_InputImageG[i][k] - 128) * s) + 128; aB = ((m_InputImageB[i][k] - 128) * s) + 128; if (aR > 255) aR = 255; else if (aR < 0) aR = 0; if (aG > 255) aG = 255; else if (aG < 0) aG = 0; if (aB > 255) aB = 255; else if (aB < 0) aB = 0; m_OutputImageR[i][k] = aR; m_OutputImageG[i][k] = aG; m_OutputImageB[i][k] = aB; } } }
명암 대비 압축 알고리즘
void OnCompressImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** double s = dlg.m_value; double aR, aG, aB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { aR = ((m_InputImageR[i][k] - 128) * s) + 128; aG = ((m_InputImageG[i][k] - 128) * s) + 128; aB = ((m_InputImageB[i][k] - 128) * s) + 128; if (aR > 255) aR = 255; else if (aR < 0) aR = 0; if (aG > 255) aG = 255; else if (aG < 0) aG = 0; if (aB > 255) aB = 255; else if (aB < 0) aB = 0; m_OutputImageR[i][k] = aR; m_OutputImageG[i][k] = aG; m_OutputImageB[i][k] = aB; } } }
포스터라이징 변환
void OnPosterizing() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int s = 255 / dlg.m_value; int aR, aG, aB; for (int i = 0; i < m_height; i++) { for (int k = 0, cnt; k < m_width; k++) { cnt = 0; aR = m_InputImageR[i][k]; for (; s * cnt < aR; cnt++); if (s * cnt > 255) m_OutputImageR[i][k] = 255; else if (s * cnt < 0) m_OutputImageR[i][k] = 0; else m_OutputImageR[i][k] = cnt * s; } } for (int i = 0; i < m_height; i++) { for (int k = 0, cnt; k < m_width; k++) { cnt = 0; aG = m_InputImageG[i][k]; for (; s * cnt < aG; cnt++); if (s * cnt > 255) m_OutputImageG[i][k] = 255; else if (s * cnt < 0) m_OutputImageG[i][k] = 0; else m_OutputImageG[i][k] = cnt * s; } } for (int i = 0; i < m_height; i++) { for (int k = 0, cnt; k < m_width; k++) { cnt = 0; aB = m_InputImageB[i][k]; for (; s * cnt < aB; cnt++); if (s * cnt > 255) m_OutputImageB[i][k] = 255; else if (s * cnt < 0) m_OutputImageB[i][k] = 0; else m_OutputImageB[i][k] = cnt * s; } } }
이진화 변환
void OnBinaryImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int avr; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { avr = (m_InputImageR[i][k] + m_InputImageG[i][k] + m_InputImageB[i][k]) / 3.0; if (avr > 128) m_OutputImageR[i][k] = 255; else if (avr <= 128) m_OutputImageR[i][k] = 0; if (avr > 128) m_OutputImageG[i][k] = 255; else if (avr <= 128) m_OutputImageG[i][k] = 0; if (avr > 128) m_OutputImageB[i][k] = 255; else if (avr <= 128) m_OutputImageB[i][k] = 0; } } }
범위 강조 변환
void OnStreTranImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CTWOQ dlg; if (dlg.DoModal() != IDOK) return; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int high = dlg.m_value1; int low = dlg.m_value2; int avr; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { avr = (m_InputImageR[i][k] + m_InputImageG[i][k] + m_InputImageB[i][k]) / 3.0; if (low <= avr && avr <= high) { m_OutputImageR[i][k] = 255; m_OutputImageG[i][k] = 255; m_OutputImageB[i][k] = 255; } else { m_OutputImageR[i][k] = m_InputImageR[i][k]; m_OutputImageG[i][k] = m_InputImageG[i][k]; m_OutputImageB[i][k] = m_InputImageB[i][k]; } } } }
확대(백워딩)
void OnZoomInBack() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; int val = dlg.m_value; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height * val; m_old_Re_height = m_Re_width = m_width * val; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { m_OutputImageR[i][k] = m_InputImageR[i/val][k/val]; m_OutputImageG[i][k] = m_InputImageG[i/val][k/val]; m_OutputImageB[i][k] = m_InputImageB[i/val][k/val]; } } }
확대(선형 보간법)
void Recur(int s, int x, int y) { int hs = s / 2; m_OutputImageR[y][x + hs] = (m_OutputImageR[y][x] + m_OutputImageR[y][x + s]) / 2; m_OutputImageR[y + hs][x] = (m_OutputImageR[y][x] + m_OutputImageR[y + s][x]) / 2; m_OutputImageR[y + hs][x + hs] = (m_OutputImageR[y][x] + m_OutputImageR[y + s][x + s]) / 2; m_OutputImageR[y + hs][x + s] = (m_OutputImageR[y][x + s] + m_OutputImageR[y + s][x + s]) / 2; m_OutputImageR[y + s][x + hs] = (m_OutputImageR[y + s][x] + m_OutputImageR[y + s][x + s]) / 2; m_OutputImageG[y][x + hs] = (m_OutputImageG[y][x] + m_OutputImageG[y][x + s]) / 2; m_OutputImageG[y + hs][x] = (m_OutputImageG[y][x] + m_OutputImageG[y + s][x]) / 2; m_OutputImageG[y + hs][x + hs] = (m_OutputImageG[y][x] + m_OutputImageG[y + s][x + s]) / 2; m_OutputImageG[y + hs][x + s] = (m_OutputImageG[y][x + s] + m_OutputImageG[y + s][x + s]) / 2; m_OutputImageG[y + s][x + hs] = (m_OutputImageG[y + s][x] + m_OutputImageG[y + s][x + s]) / 2; m_OutputImageB[y][x + hs] = (m_OutputImageB[y][x] + m_OutputImageB[y][x + s]) / 2; m_OutputImageB[y + hs][x] = (m_OutputImageB[y][x] + m_OutputImageB[y + s][x]) / 2; m_OutputImageB[y + hs][x + hs] = (m_OutputImageB[y][x] + m_OutputImageB[y + s][x + s]) / 2; m_OutputImageB[y + hs][x + s] = (m_OutputImageB[y][x + s] + m_OutputImageB[y + s][x + s]) / 2; m_OutputImageB[y + s][x + hs] = (m_OutputImageB[y + s][x] + m_OutputImageB[y + s][x + s]) / 2; if (hs > 1) { Recur(hs, x, y); Recur(hs, x + hs, y); Recur(hs, x, y + hs); Recur(hs, x + hs, y + hs); } } void OnLinear() { if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 –> 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; int scale = dlg.m_value; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height * scale; m_old_Re_height = m_Re_width = m_width * scale; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for(int i=0;i 알고리즘에 따름.. CONEQ dlg; if (dlg.DoModal() != IDOK) return; double val = dlg.m_value; freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height / val; m_old_Re_height = m_Re_width = m_width / val; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { m_OutputImageR[i][k] = m_InputImageR[i * (int)val][k * (int)val]; m_OutputImageG[i][k] = m_InputImageG[i * (int)val][k * (int)val]; m_OutputImageB[i][k] = m_InputImageB[i * (int)val][k * (int)val]; } } }
회전(백워딩,중심점,크기 보정)
void OnCnbnzRotate() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; CONEQ dlg; if (dlg.DoModal() != IDOK) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. double value = dlg.m_value; double rad = value * 3.141592 / 180.0; double w = m_height * abs(cos(90.0 * 3.141592 / 180.0 – rad)) + m_width * abs(cos(rad)); double h = m_height * abs(cos(rad)) + m_width * abs(cos(90.0 * 3.141592 / 180.0 – rad)); freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = (int)h; m_old_Re_width = m_Re_width = (int)w; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int dx, dy, hy = m_height-1; int ocx = m_width / 2.0; int ocy = m_height / 2.0; int cx = w / 2.0; int cy = h / 2.0; for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { dx = ((k - cx) * cos(rad)) - ((i - cy) * sin(rad)) + ocx; dy = ((k - cx) * sin(rad)) + ((i - cy) * cos(rad)) + ocy; if ((0<=dx && dx < m_width) && (0 <= dy && dy < m_height)) { m_OutputImageR[i][k] = m_InputImageR[dy][dx]; m_OutputImageG[i][k] = m_InputImageG[dy][dx]; m_OutputImageB[i][k] = m_InputImageB[dy][dx]; } } } }
히스토그램 스트레치
void OnHistogram() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** int R, G, B, o; int minR, maxR, minG, maxG, minB, maxB; minR = m_InputImageR[0][0], maxR = m_InputImageR[0][0]; for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { if (m_InputImageR[i][k] > maxR) maxR = m_InputImageR[i][k]; if (m_InputImageR[i][k] < minR) minR = m_InputImageR[i][k]; } minG = m_InputImageG[0][0], maxG = m_InputImageG[0][0]; for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { if (m_InputImageG[i][k] > maxG) maxG = m_InputImageG[i][k]; if (m_InputImageG[i][k] < minG) minG = m_InputImageG[i][k]; } minB = m_InputImageB[0][0], maxB = m_InputImageB[0][0]; for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { if (m_InputImageB[i][k] > maxB) maxB = m_InputImageB[i][k]; if (m_InputImageB[i][k] < minB) minB = m_InputImageB[i][k]; } for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { R = (m_InputImageR[i][k] - minR) / (double)(maxR - minR) * 255; G = (m_InputImageG[i][k] - minG) / (double)(maxG - minG) * 255; B = (m_InputImageB[i][k] - minB) / (double)(maxB - minB) * 255; if (R > 255) m_OutputImageR[i][k] = 255; else if (R < 0) m_OutputImageR[i][k] = 0; else if (0 <= R && R < 256) m_OutputImageR[i][k] = R; if (G > 255) m_OutputImageG[i][k] = 255; else if (G < 0) m_OutputImageG[i][k] = 0; else if (0 <= G && G < 256) m_OutputImageG[i][k] = G; if (B > 255) m_OutputImageB[i][k] = 255; else if (B < 0) m_OutputImageB[i][k] = 0; else if (0 <= B && B < 256) m_OutputImageB[i][k] = B; } } }
히스토그램 엔드인탐색
void OnEndInSearch() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** CTWOQ dlg; if (dlg.DoModal() != IDOK) return; int min = dlg.m_value2, max = dlg.m_value1; int R, G, B; int AR, AG, AB; double avr; for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { R = m_InputImageR[i][k]; G = m_InputImageG[i][k]; B = m_InputImageB[i][k]; avr = (R + G + B) / 3.0; R = ((m_InputImageR[i][k] - avr) - min) / (double)(max - min) * 255; G = ((m_InputImageG[i][k] - avr)- min) / (double)(max - min) * 255; B = ((m_InputImageB[i][k] - avr) - min) / (double)(max - min) * 255; avr = (avr - min) / (double)(max - min) * 255; /* AR = (avr - min) / (double)(max - min) * 255; AG = (avr - min) / (double)(max - min) * 255; AB = (avr - min) / (double)(max - min) * 255;*/ R += avr; G += avr; B += avr; if (R > max) m_OutputImageR[i][k] = 255; else if (R < min) m_OutputImageR[i][k] = 0; else if (min <= R && R < max) m_OutputImageR[i][k] = R; if (G > max) m_OutputImageG[i][k] = 255; else if (G < min) m_OutputImageG[i][k] = 0; else if (min <= G && G < max) m_OutputImageG[i][k] = G; if (B > max) m_OutputImageB[i][k] = 255; else if (B < min) m_OutputImageB[i][k] = 0; else if (min <= B && B < max) m_OutputImageB[i][k] = B; } } }
평활화
void RGBtoHSV(int R, int G, int B, double* H, double* S, double* V) { // TODO: 여기에 구현 코드 추가. //R, G and B input range = 0 ÷ 255 //H, S and V output range = 0 ÷ 1.0 double var_R = (R / 255.0); double var_G = (G / 255.0); double var_B = (B / 255.0); double var_Min = min(min(var_R, var_G), var_B); //Min. value of RGB double var_Max = max(max(var_R, var_G), var_B); //Max. value of RGB double del_Max = var_Max - var_Min; //Delta RGB value *V = var_Max; if (del_Max == 0) //This is a gray, no chroma... { *H = 0; *S = 0; } else //Chromatic data... { *S = del_Max / var_Max; double del_R = (((var_Max - var_R) / 6.0) + (del_Max / 2.0)) / del_Max; double del_G = (((var_Max - var_G) / 6.0) + (del_Max / 2.0)) / del_Max; double del_B = (((var_Max - var_B) / 6.0) + (del_Max / 2.0)) / del_Max; if (var_R == var_Max) *H = del_B - del_G; else if (var_G == var_Max) *H = (1 / 3.0) + del_R - del_B; else if (var_B == var_Max) *H = (2 / 3.0) + del_G - del_R; if (*H < 0.0) *H += 1; if (*H > 1.0) *H -= 1; } } void HSVtoRGB(unsigned char* R, unsigned char* G,unsigned char* B, double H, double S, double V) { // TODO: 여기에 구현 코드 추가. //H, S and V input range = 0 ÷ 1.0 //R, G and B output range = 0 ÷ 255 if (S == 0) { *R = V * 255; *G = V * 255; *B = V * 255; } else { double var_h = H * 6; if (var_h == 6) var_h = 0; //H must be < 1 int var_i = int(var_h); //Or ... var_i = floor( var_h ) double var_1 = V * (1 - S); double var_2 = V * (1 - S * (var_h - var_i)); double var_3 = V * (1 - S * (1 - (var_h - var_i))); double var_r, var_g, var_b; if (var_i == 0) { var_r = V; var_g = var_3; var_b = var_1; } else if (var_i == 1) { var_r = var_2; var_g = V; var_b = var_1; } else if (var_i == 2) { var_r = var_1; var_g = V; var_b = var_3; } else if (var_i == 3) { var_r = var_1; var_g = var_2; var_b = V; } else if (var_i == 4) { var_r = var_3; var_g = var_1; var_b = V; } else { var_r = V; var_g = var_1; var_b = var_2; } //var_r *= 255; *R = var_r * 255.0; *G = var_g * 255.0; *B = var_b * 255.0; } } double** malloc2D_double(int h, int w) { // TODO: 여기에 구현 코드 추가. double** p; p = (double**)malloc(h * sizeof(double*)); for (int i = 0; i < h; i++) p[i] = (double*)malloc(w * sizeof(double)); return p; } void OnEqualized() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); double** TempImageH = malloc2D_double(m_Re_height, m_Re_width); double** TempImageS = malloc2D_double(m_Re_height, m_Re_width); double** TempImageV = malloc2D_double(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { double* pH, * pS, * pV; int R, G, B; pH = &TempImageH[i][k]; pS = &TempImageS[i][k]; pV = &TempImageV[i][k]; R = m_InputImageR[i][k]; G = m_InputImageG[i][k]; B = m_InputImageB[i][k]; RGBtoHSV(R, G, B, pH, pS, pV); } int sumV[256] = { 0, }, cntV[256] = { 0, }; //int sumS[256] = { 0, }, cntS[256] = { 0, }; for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { cntV[(int)(TempImageV[i][k] * 255.0)]++; //cntS[(int)(TempImageS[i][k] * 255.0)]++; } int sV = 0; //int sS = 0; double nV[256] = { 0.0, }; //double nS[256] = { 0.0, }; for (int i = 0; i < 256; i++) { sV += cntV[i]; //sS += cntS[i]; sumV[i] = sV; //sumS[i] = sS; } for (int i = 0; i < 256; i++) { nV[i] = (double)sumV[i] * (1.0 / sumV[255]) * 255.0; //nS[i] = (double)sumS[i] * (1.0 / sumS[255]) * 255.0; } for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { TempImageV[i][k] = nV[(int)(TempImageV[i][k] * 255)] / 255.0; //TempImageS[i][k] = nS[(int)(TempImageS[i][k] * 255)] / 255.0; } unsigned char* pR, * pG, * pB; double H, S, V; for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_height; k++) { H = TempImageH[i][k]; S = TempImageS[i][k]; V = TempImageV[i][k]; pR = &m_OutputImageR[i][k]; pG = &m_OutputImageG[i][k]; pB = &m_OutputImageB[i][k]; HSVtoRGB(pR, pG, pB, H, S, V); } for (int i = 0; i < m_Re_height; i++) { free(TempImageH[i]); free(TempImageS[i]); free(TempImageV[i]); } TempImageH = NULL; TempImageS = NULL; TempImageV = NULL; }
엠보싱
void freeTemp(double** p, int h) { // TODO: 여기에 구현 코드 추가. if (p != NULL) { for (int i = 0; i < h; i++) free(p[i]); free(p); } p = NULL; } void OnEmbossing() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** //마스크 double mask[3][3] = { {-1.0,0.0,0.0}, { 0.0,0.0,0.0}, { 0.0,0.0,1.0} }; //임시 입출메모리 확보 double** tmpInput, ** tmpOutput; tmpInput = malloc2D_double(m_height + 2, m_width + 2); tmpOutput = malloc2D_double(m_height, m_width); //input->tempinput for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) tmpInput[i + 1][k + 1] = (double)m_InputImageR[i][k]; double S; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { S = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { S += tmpInput[i + m][k + n] * mask[m][n]; } } tmpOutput[i][k] = S; } } //마스크 총합이 0이면 127을 더하기. for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) tmpOutput[i][k] += 127.0; //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { if (tmpOutput[i][k] > 255.0) m_OutputImageR[i][k] = 255; else if (tmpOutput[i][k] < 0.0) m_OutputImageR[i][k] = 0; else m_OutputImageR[i][k] = (int)tmpOutput[i][k]; } for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) tmpInput[i + 1][k + 1] = (double)m_InputImageG[i][k]; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { S = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { S += tmpInput[i + m][k + n] * mask[m][n]; } } tmpOutput[i][k] = S; } } //마스크 총합이 0이면 127을 더하기. for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) tmpOutput[i][k] += 127.0; //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { if (tmpOutput[i][k] > 255.0) m_OutputImageG[i][k] = 255; else if (tmpOutput[i][k] < 0.0) m_OutputImageG[i][k] = 0; else m_OutputImageG[i][k] = (int)tmpOutput[i][k]; } for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) tmpInput[i + 1][k + 1] = (double)m_InputImageB[i][k]; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { S = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { S += tmpInput[i + m][k + n] * mask[m][n]; } } tmpOutput[i][k] = S; } } //마스크 총합이 0이면 127을 더하기. for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) tmpOutput[i][k] += 127.0; //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { if (tmpOutput[i][k] > 255.0) m_OutputImageB[i][k] = 255; else if (tmpOutput[i][k] < 0.0) m_OutputImageB[i][k] = 0; else m_OutputImageB[i][k] = (int)tmpOutput[i][k]; } freeTemp(tmpInput, m_height + 2); freeTemp(tmpOutput, m_height); }
블러
void OnBlur() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** //마스크 double mask[3][3] = { {1.0 / 9.0,1.0 / 9.0,1.0 / 9.0}, { 1.0 / 9.0,1.0 / 9.0,1.0 / 9.0}, { 1.0 / 9.0,1.0 / 9.0,1.0 / 9.0} }; //임시 입출메모리 확보 double** tmpInputR, ** tmpOutputR, ** tmpInputG, ** tmpOutputG, ** tmpInputB, ** tmpOutputB; tmpInputR = malloc2D_double(m_height + 2, m_width + 2); tmpInputG = malloc2D_double(m_height + 2, m_width + 2); tmpInputB = malloc2D_double(m_height + 2, m_width + 2); tmpOutputR = malloc2D_double(m_height, m_width); tmpOutputG = malloc2D_double(m_height, m_width); tmpOutputB = malloc2D_double(m_height, m_width); //input->tempinput for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) { tmpInputR[i + 1][k + 1] = (double)m_InputImageR[i][k]; tmpInputG[i + 1][k + 1] = (double)m_InputImageG[i][k]; tmpInputB[i + 1][k + 1] = (double)m_InputImageB[i][k]; } double SR, SG, SB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { SR = 0.0, SG = 0.0, SB = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { SR += tmpInputR[i + m][k + n] * mask[m][n]; SG += tmpInputG[i + m][k + n] * mask[m][n]; SB += tmpInputB[i + m][k + n] * mask[m][n]; } } tmpOutputR[i][k] = SR; tmpOutputG[i][k] = SG; tmpOutputB[i][k] = SB; } } //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { if (tmpOutputR[i][k] > 255.0) m_OutputImageR[i][k] = 255; else if (tmpOutputR[i][k] < 0.0) m_OutputImageR[i][k] = 0; else m_OutputImageR[i][k] = (int)tmpOutputR[i][k]; } for (int k = 0; k < m_Re_width; k++) { if (tmpOutputG[i][k] > 255.0) m_OutputImageG[i][k] = 255; else if (tmpOutputG[i][k] < 0.0) m_OutputImageG[i][k] = 0; else m_OutputImageG[i][k] = (int)tmpOutputG[i][k]; } for (int k = 0; k < m_Re_width; k++) { if (tmpOutputB[i][k] > 255.0) m_OutputImageB[i][k] = 255; else if (tmpOutputB[i][k] < 0.0) m_OutputImageB[i][k] = 0; else m_OutputImageB[i][k] = (int)tmpOutputB[i][k]; } } freeTemp(tmpInputR, m_height + 2); freeTemp(tmpOutputR, m_height); freeTemp(tmpInputG, m_height + 2); freeTemp(tmpOutputG, m_height); freeTemp(tmpInputB, m_height + 2); freeTemp(tmpOutputB, m_height); }
가우시안 스무딩 필터
void OnSmoothing() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** //마스크 double mask[3][3] = { {1.0 / 16.0,1.0 / 8.0,1.0 / 16.0}, { 1.0 / 8.0,1.0 / 4.0,1.0 / 8.0}, { 1.0 / 16.0,1.0 / 8.0,1.0 / 16.0} }; //임시 입출메모리 확보 double** tmpInputR, ** tmpOutputR, ** tmpInputG, ** tmpOutputG, ** tmpInputB, ** tmpOutputB; tmpInputR = malloc2D_double(m_height + 2, m_width + 2); tmpInputG = malloc2D_double(m_height + 2, m_width + 2); tmpInputB = malloc2D_double(m_height + 2, m_width + 2); tmpOutputR = malloc2D_double(m_height, m_width); tmpOutputG = malloc2D_double(m_height, m_width); tmpOutputB = malloc2D_double(m_height, m_width); //input->tempinput for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) { tmpInputR[i + 1][k + 1] = (double)m_InputImageR[i][k]; tmpInputG[i + 1][k + 1] = (double)m_InputImageG[i][k]; tmpInputB[i + 1][k + 1] = (double)m_InputImageB[i][k]; } double SR, SG, SB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { SR = 0.0, SG = 0.0, SB = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { SR += tmpInputR[i + m][k + n] * mask[m][n]; SG += tmpInputG[i + m][k + n] * mask[m][n]; SB += tmpInputB[i + m][k + n] * mask[m][n]; } } tmpOutputR[i][k] = SR; tmpOutputG[i][k] = SG; tmpOutputB[i][k] = SB; } } //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { if (tmpOutputR[i][k] > 255.0) m_OutputImageR[i][k] = 255; else if (tmpOutputR[i][k] < 0.0) m_OutputImageR[i][k] = 0; else m_OutputImageR[i][k] = (int)tmpOutputR[i][k]; } for (int k = 0; k < m_Re_width; k++) { if (tmpOutputG[i][k] > 255.0) m_OutputImageG[i][k] = 255; else if (tmpOutputG[i][k] < 0.0) m_OutputImageG[i][k] = 0; else m_OutputImageG[i][k] = (int)tmpOutputG[i][k]; } for (int k = 0; k < m_Re_width; k++) { if (tmpOutputB[i][k] > 255.0) m_OutputImageB[i][k] = 255; else if (tmpOutputB[i][k] < 0.0) m_OutputImageB[i][k] = 0; else m_OutputImageB[i][k] = (int)tmpOutputB[i][k]; } } freeTemp(tmpInputR, m_height + 2); freeTemp(tmpOutputR, m_height); freeTemp(tmpInputG, m_height + 2); freeTemp(tmpOutputG, m_height); freeTemp(tmpInputB, m_height + 2); freeTemp(tmpOutputB, m_height); }
샤프닝
void OnSharpning() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** //마스크 double mask[3][3] = { {0.0,-1.0,0.0}, { -1.0,5.0,-1.0}, {0.0,-1.0,0.0} }; //임시 입출메모리 확보 double** tmpInputR, ** tmpOutputR, ** tmpInputG, ** tmpOutputG, ** tmpInputB, ** tmpOutputB; tmpInputR = malloc2D_double(m_height + 2, m_width + 2); tmpInputG = malloc2D_double(m_height + 2, m_width + 2); tmpInputB = malloc2D_double(m_height + 2, m_width + 2); tmpOutputR = malloc2D_double(m_height, m_width); tmpOutputG = malloc2D_double(m_height, m_width); tmpOutputB = malloc2D_double(m_height, m_width); //input->tempinput for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) { tmpInputR[i + 1][k + 1] = (double)m_InputImageR[i][k]; tmpInputG[i + 1][k + 1] = (double)m_InputImageG[i][k]; tmpInputB[i + 1][k + 1] = (double)m_InputImageB[i][k]; } double SR, SG, SB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { SR = 0.0, SG = 0.0, SB = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { SR += tmpInputR[i + m][k + n] * mask[m][n]; SG += tmpInputG[i + m][k + n] * mask[m][n]; SB += tmpInputB[i + m][k + n] * mask[m][n]; } } tmpOutputR[i][k] = SR; tmpOutputG[i][k] = SG; tmpOutputB[i][k] = SB; } } //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { if (tmpOutputR[i][k] > 255.0) m_OutputImageR[i][k] = 255; else if (tmpOutputR[i][k] < 0.0) m_OutputImageR[i][k] = 0; else m_OutputImageR[i][k] = (int)tmpOutputR[i][k]; } for (int k = 0; k < m_Re_width; k++) { if (tmpOutputG[i][k] > 255.0) m_OutputImageG[i][k] = 255; else if (tmpOutputG[i][k] < 0.0) m_OutputImageG[i][k] = 0; else m_OutputImageG[i][k] = (int)tmpOutputG[i][k]; } for (int k = 0; k < m_Re_width; k++) { if (tmpOutputB[i][k] > 255.0) m_OutputImageB[i][k] = 255; else if (tmpOutputB[i][k] < 0.0) m_OutputImageB[i][k] = 0; else m_OutputImageB[i][k] = (int)tmpOutputB[i][k]; } } freeTemp(tmpInputR, m_height + 2); freeTemp(tmpOutputR, m_height); freeTemp(tmpInputG, m_height + 2); freeTemp(tmpOutputG, m_height); freeTemp(tmpInputB, m_height + 2); freeTemp(tmpOutputB, m_height); }
고주파 통과 필터
void OnHpf() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** //마스크 double mask[3][3] = { {-1.0 / 9.0,-1.0 / 9.0,-1.0 / 9.0}, { -1.0 / 9.0,8.0 / 9.0,-1.0 / 9.0}, {-1.0 / 9.0,-1.0 / 9.0,-1.0 / 9.0} }; //임시 입출메모리 확보 double** tmpInputR, ** tmpOutputR, ** tmpInputG, ** tmpOutputG, ** tmpInputB, ** tmpOutputB; tmpInputR = malloc2D_double(m_height + 2, m_width + 2); tmpInputG = malloc2D_double(m_height + 2, m_width + 2); tmpInputB = malloc2D_double(m_height + 2, m_width + 2); tmpOutputR = malloc2D_double(m_height, m_width); tmpOutputG = malloc2D_double(m_height, m_width); tmpOutputB = malloc2D_double(m_height, m_width); //input->tempinput for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) { tmpInputR[i + 1][k + 1] = (double)m_InputImageR[i][k]; tmpInputG[i + 1][k + 1] = (double)m_InputImageG[i][k]; tmpInputB[i + 1][k + 1] = (double)m_InputImageB[i][k]; } double SR, SG, SB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { SR = 0.0, SG = 0.0, SB = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { SR += tmpInputR[i + m][k + n] * mask[m][n]; SG += tmpInputG[i + m][k + n] * mask[m][n]; SB += tmpInputB[i + m][k + n] * mask[m][n]; } } tmpOutputR[i][k] = SR; tmpOutputG[i][k] = SG; tmpOutputB[i][k] = SB; } } //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { if (tmpOutputR[i][k] > 255.0) m_OutputImageR[i][k] = 255; else if (tmpOutputR[i][k] < 0.0) m_OutputImageR[i][k] = 0; else m_OutputImageR[i][k] = (int)tmpOutputR[i][k]; } for (int k = 0; k < m_Re_width; k++) { if (tmpOutputG[i][k] > 255.0) m_OutputImageG[i][k] = 255; else if (tmpOutputG[i][k] < 0.0) m_OutputImageG[i][k] = 0; else m_OutputImageG[i][k] = (int)tmpOutputG[i][k]; } for (int k = 0; k < m_Re_width; k++) { if (tmpOutputB[i][k] > 255.0) m_OutputImageB[i][k] = 255; else if (tmpOutputB[i][k] < 0.0) m_OutputImageB[i][k] = 0; else m_OutputImageB[i][k] = (int)tmpOutputB[i][k]; } } freeTemp(tmpInputR, m_height + 2); freeTemp(tmpOutputR, m_height); freeTemp(tmpInputG, m_height + 2); freeTemp(tmpOutputG, m_height); freeTemp(tmpInputB, m_height + 2); freeTemp(tmpOutputB, m_height); }
언샤프닝(원본-저주파 통과 이미지)
void OnLpf() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** //마스크 double mask[3][3] = { {1.0 / 9.0,1.0 / 9.0,1.0 / 9.0}, { 1.0 / 9.0,1.0 / 9.0,1.0 / 9.0}, { 1.0 / 9.0,1.0 / 9.0,1.0 / 9.0} }; //임시 입출메모리 확보 double** tmpInputR, ** tmpOutputR, ** tmpInputG, ** tmpOutputG, ** tmpInputB, ** tmpOutputB; tmpInputR = malloc2D_double(m_height + 2, m_width + 2); tmpInputG = malloc2D_double(m_height + 2, m_width + 2); tmpInputB = malloc2D_double(m_height + 2, m_width + 2); tmpOutputR = malloc2D_double(m_height, m_width); tmpOutputG = malloc2D_double(m_height, m_width); tmpOutputB = malloc2D_double(m_height, m_width); //input->tempinput for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) { tmpInputR[i + 1][k + 1] = (double)m_InputImageR[i][k]; tmpInputG[i + 1][k + 1] = (double)m_InputImageG[i][k]; tmpInputB[i + 1][k + 1] = (double)m_InputImageB[i][k]; } double SR, SG, SB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { SR = 0.0, SG = 0.0, SB = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { SR += tmpInputR[i + m][k + n] * mask[m][n]; SG += tmpInputG[i + m][k + n] * mask[m][n]; SB += tmpInputB[i + m][k + n] * mask[m][n]; } } tmpOutputR[i][k] = SR; tmpOutputG[i][k] = SG; tmpOutputB[i][k] = SB; } } //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { SR = m_InputImageR[i][k] - tmpOutputR[i][k]; if (SR > 255.0) m_OutputImageR[i][k] = 255; else if (SR < 0.0) m_OutputImageR[i][k] = 0; else m_OutputImageR[i][k] = (int)SR; } for (int k = 0; k < m_Re_width; k++) { SG = m_InputImageR[i][k] - tmpOutputR[i][k]; if (SG > 255.0) m_OutputImageG[i][k] = 255; else if (SG < 0.0) m_OutputImageG[i][k] = 0; else m_OutputImageG[i][k] = (int)SG; } for (int k = 0; k < m_Re_width; k++) { SB = m_InputImageR[i][k] - tmpOutputR[i][k]; if (SB > 255.0) m_OutputImageB[i][k] = 255; else if (SB < 0.0) m_OutputImageB[i][k] = 0; else m_OutputImageB[i][k] = (int)SB; } } freeTemp(tmpInputR, m_height + 2); freeTemp(tmpOutputR, m_height); freeTemp(tmpInputG, m_height + 2); freeTemp(tmpOutputG, m_height); freeTemp(tmpInputB, m_height + 2); freeTemp(tmpOutputB, m_height); }
이미지 이동 엣지검출
void OnShift() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** //마스크 double mask[3][3] = { {0.0,-1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,0.0} }; //임시 입출메모리 확보 double** tmpInputR, ** tmpOutputR, ** tmpInputG, ** tmpOutputG, ** tmpInputB, ** tmpOutputB; tmpInputR = malloc2D_double(m_height + 2, m_width + 2); tmpInputG = malloc2D_double(m_height + 2, m_width + 2); tmpInputB = malloc2D_double(m_height + 2, m_width + 2); tmpOutputR = malloc2D_double(m_height, m_width); tmpOutputG = malloc2D_double(m_height, m_width); tmpOutputB = malloc2D_double(m_height, m_width); //input->tempinput for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) { tmpInputR[i + 1][k + 1] = (double)m_InputImageR[i][k]; tmpInputG[i + 1][k + 1] = (double)m_InputImageG[i][k]; tmpInputB[i + 1][k + 1] = (double)m_InputImageB[i][k]; } double SR, SG, SB; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { SR = 0.0, SG = 0.0, SB = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { SR += tmpInputR[i + m][k + n] * mask[m][n]; SG += tmpInputG[i + m][k + n] * mask[m][n]; SB += tmpInputB[i + m][k + n] * mask[m][n]; } } tmpOutputR[i][k] = SR; tmpOutputG[i][k] = SG; tmpOutputB[i][k] = SB; } } //임시 output -->진짜 output for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { SR = tmpOutputR[i][k]; if (SR > 255.0) m_OutputImageR[i][k] = 255; else if (SR < 0.0) m_OutputImageR[i][k] = 0; else m_OutputImageR[i][k] = (int)SR; } for (int k = 0; k < m_Re_width; k++) { SG = tmpOutputR[i][k]; if (SG > 255.0) m_OutputImageG[i][k] = 255; else if (SG < 0.0) m_OutputImageG[i][k] = 0; else m_OutputImageG[i][k] = (int)SG; } for (int k = 0; k < m_Re_width; k++) { SB = tmpOutputR[i][k]; if (SB > 255.0) m_OutputImageB[i][k] = 255; else if (SB < 0.0) m_OutputImageB[i][k] = 0; else m_OutputImageB[i][k] = (int)SB; } } freeTemp(tmpInputR, m_height + 2); freeTemp(tmpOutputR, m_height); freeTemp(tmpInputG, m_height + 2); freeTemp(tmpOutputG, m_height); freeTemp(tmpInputB, m_height + 2); freeTemp(tmpOutputB, m_height); }
유사연산자 엣지검출
void OnHomogenOperator() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** //마스크 double mask[3][3] = { {1.0,1.0,1.0}, {1.0,1.0,1.0}, {1.0,1.0,1.0} }; //임시 입출메모리 확보 double** tmpInput, ** tmpOutput; tmpInput = malloc2D_double(m_height + 2, m_width + 2); tmpOutput = malloc2D_double(m_height, m_width); //input->tempinput for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) { tmpInput[i + 1][k + 1] = (m_InputImageR[i][k] + m_InputImageG[i][k] + m_InputImageB[i][k]) / 3.0; } double S, dif; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { dif = 0.0; for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++) { S = tmpInput[i + 1][k + 1] - tmpInput[i + m][k + n]; if (S > dif) dif = S; } } tmpOutput[i][k] = dif; } } double t; for (int i = 0; i < m_Re_height; i++) { for (int k = 0; k < m_Re_width; k++) { t = tmpOutput[i][k]; if (t > 255.0) t = 255.0; if (t < 0.0) t = 0.0; m_OutputImageR[i][k] = (unsigned char)m_InputImageR[i][k] * (t / 255); m_OutputImageG[i][k] = (unsigned char)m_InputImageG[i][k] * (t / 255); m_OutputImageB[i][k] = (unsigned char)m_InputImageB[i][k] * (t / 255); } } }
평균값 이진화
void OnAverageBinary() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** long sum = 0; for (int i = 0; i < m_height; i++) for (int k = 0; k < m_width; k++) sum += m_InputImageR[i][k] + m_InputImageG[i][k] + m_InputImageB[i][k]; int avr = (double)sum / (double)(m_height * m_width) / 3.0; int a; for (int i = 0; i < m_height; i++) { for (int k = 0; k < m_width; k++) { a = (m_InputImageR[i][k] + m_InputImageG[i][k] + m_InputImageB[i][k]) / 3.0; if (avr > a) { m_OutputImageR[i][k] = 0; m_OutputImageG[i][k] = 0; m_OutputImageB[i][k] = 0; } else { m_OutputImageR[i][k] = 255; m_OutputImageG[i][k] = 255; m_OutputImageB[i][k] = 255; } } } }
이미지 이동
void OnMoveImage() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 –> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** CTWOQ dlg; if (dlg.DoModal() != IDOK) return; int x = (int)dlg.m_value1; int y = (int)dlg.m_value2; for(int i=0;i 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { m_OutputImageR[i][k] = m_InputImageR[i][m_Re_width - k - 1]; m_OutputImageG[i][k] = m_InputImageG[i][m_Re_width - k - 1]; m_OutputImageB[i][k] = m_InputImageB[i][m_Re_width - k - 1]; } }
이미지 상하반전
void OnMirrorUd() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { m_OutputImageR[i][k] = m_InputImageR[m_Re_height -1 -i][k]; m_OutputImageG[i][k] = m_InputImageG[m_Re_height - 1 - i][k]; m_OutputImageB[i][k] = m_InputImageB[m_Re_height - 1 - i][k]; } }
이미지 상하좌우반전
void OnMirror() { // TODO: 여기에 구현 코드 추가. if (m_InputImageR == NULL) return; // *중요* 출력영상의 크기 결정 --> 알고리즘에 따름.. freeOutputImage(m_old_Re_height); m_old_Re_height = m_Re_height = m_height; m_old_Re_height = m_Re_width = m_width; // 출력 이미지 메모리 할당 m_OutputImageR = malloc2D(m_Re_height, m_Re_width); m_OutputImageG = malloc2D(m_Re_height, m_Re_width); m_OutputImageB = malloc2D(m_Re_height, m_Re_width); // **** 진짜 영상 처리 알고리즘 *** for (int i = 0; i < m_Re_height; i++) for (int k = 0; k < m_Re_width; k++) { m_OutputImageR[i][k] = m_InputImageR[m_Re_height - 1 - i][m_Re_width - k - 1]; m_OutputImageG[i][k] = m_InputImageG[m_Re_height - 1 - i][m_Re_width - k - 1]; m_OutputImageB[i][k] = m_InputImageB[m_Re_height - 1 - i][m_Re_width - k - 1]; } }
OpenCV를 이용해서 간단한 이미지, 영상의 In/Out 처리 를 해보며 사용되는 코드 분석을 해보겠습니다.(Image Processing/Video Processing)
먼저, 개념들에 대해서 간단하게 설명한 후 시작하도록 하겠습니다.
OpenCV(Open Source Computer Vision Library)
-Intel사에서 1999년에 처음 발표된 영상처리 및 컴퓨터 비전 라이브러리이며, 현재는 OpenCV Foundation에서 프로젝트 관리가 이루어지고 있습니다
-현재까지는 4.4.0버전까지 배포되었습니다.
-영상의 파일 및 화면 입출력, 다양한 변환과정, 공간 변환, 영상 분할, 히스토그램 분석 및 처리 등 다양한 기능을 가지고 있습니다.
(이 글에서는 OpenCV-3.1.0으로 학습을 진행해보겠습니다.)
설치과정은 아래 링크를 참고하시기 바랍니다.
https://docs.opencv.org/3.1.0/d5/de5/tutorial_py_setup_in_windows.html
윈도우일 경우, 시스템 환경변수를 추가해야하고, visual studio에서 라이브러리를 찾을 수 있도록 몇가지 수정해야 한다는 점 유의하시기 바랍니다.
설치가 완료되었다면, 예제를 통해 통해 살펴본 후, 코드 분석을 통해 자세한 설명을 진행하겠습니다.
#include using namespace cv; void main() { //Mat객체 변수인 Image에 lena.jpg파일을 읽어서 저장. Mat Image = imread(“lena.jpg”, IMREAD_COLOR); //간단한 위도우 이름설정하고 사이즈는 자동할당으로 지정. namedWindow(“display”, WINDOW_AUTOSIZE); //윈도우 이름과 윈도우에 보여주고자하는 변수명을 imshow를 통해 입력. imshow(“display”, Image); //저장하고자 하는 이미지 파일이음.파일확장자와 저장하고싶은 이미지 imwrite(“lena_new.jpg”, Image); waitKey(0); }
-> 간단히 프로젝트 폴더에 있는 이미지를 읽어와서 새로운 파일명으로 저장해보는 예제입니다.
-> 여기서 Mat 클래스는 여러 채널의 실수나 행렬, 영상 등의 수치 데이터를 표현하는 N차원 행렬 클래스입니다.
간단히 말하자면 “비정형 데이터에서 수치를 표현해주는 행렬바구니”로 이해하면 될 것 같습니다.
또한 Data Type& Channel Pattern을 살펴보면
CV_8UC1 : 8 비트 픽셀/부호가 없는 정수/1채널
CV_16SC3 : 16 비트 픽셀/부호가 있는 정수/3채널
CV_32FC4 : 32 비트 픽셀/부동 소수점 방식/4채널
이와 같은 표현합니다. (U: unsigned, S: signed, F: float이고 앞의 숫자는 비트, 뒤의 숫자는 채널을 의미합니다.)
추가적으로 헤더파일 다음에 namespace cv를 사용했는데, cv::의 주요 메소드는
-imread, imwrite, imshow, waitkey등이 있습니다.(waitkey(0)은 키보드 입력이 들어올 때 까지 무한 대기한다는 의미입니다)
다음은 영상 처리 예제를 살펴보겠습니다.
#include using namespace cv; void main() { VideoCapture capture(“video.mp4”); Mat Frame; //Frame변수에 프레임을 저장할 것이다. if (!capture.isOpened()) // 비디오캡쳐가 되지 않았을 때(불러오지 못했을 때) { printf(“Video file can not open
“); return; } namedWindow(“video”); while (1) { capture >> Frame;//캡처한 비디오 프레임을 Mat변수 Frame에 저장. if (Frame.empty())//프레임이 끝났을 때 즉, 일 다했으면 나가라. break; imshow(“video”, Frame); //출력 창에 캡쳐된 프레임을 출력해라 if (waitKey(10) > 0) break; } }
-> 간단한 영상을 읽어와서 프레임단위로 출력해보는 예제입니다.
전에 진행했던 Image클래스에서는 Mat클래스를 사용하여 불러오고 저장하였지만 영상을 가져올 때는 먼저! VideoCapture클래스로 가져오고 >>연산자로 Mat객체에 넘겨주는 과정이 보이 실겁니다.
+영상 처리 활용
그러면 실제 영상을 만들어서 프레임 단위로 읽어 프레임을 제일 끝부분 부터 출력해보겠습니다(영상 역순 출력)
#include #include #include using namespace cv; using namespace std; void main() { VideoCapture capture(“Test321count.mp4”); Mat frame; if (!capture.isOpened()) { printf(“video file cannot open
“); return; } VideoWriter writer; vector video; writer.open(“Reverse321count.avi”, CV_FOURCC(‘D’, ‘I’, ‘V’, ‘X’), 30, Size(1920, 1080), true); while (1) { Mat frame; capture >> frame; if (frame.empty()) break; video.push_back(frame); } for (int i = 0;i < video.size();i++) writer.write(video[video.size() - (i + 1)]); }
-> ‘Test321count’라는 을 videocapture클래스로 가져와서 역순으로 출력할 것이기 때문에 플레임 순서를 가리키고 작업을 진행해야 하므로 Vector를 사용하였습니다.
-또한 비디오를 작성하기 위한 클래스인 VideoWriter를 써서 writer.open으로 어떤 유형의 파일을 만들것인지 설정해준 다음 video벡터에 Push_back(프레임)으로 프레임 하나씩 넣어준다음, video끝부분 부터 iterating하여 writer.write로 적어주었습니다.
쉽게 말하면, 프레임을 담기 위해서는 Mat라는 바구니가 필요하고 그 바구니의 처음과 끝을 가리키기 위해 vector를 선언했고, whlie반복문을 사용하여 하나씩 push_back을 하였습니다.
//CV_FOURCC부분은 프레임을 압축하는데 사용되는 4자리의 코덱이며
코덱목록은 아래 링크를 참고하시기 바랍니다.
http://www.fourcc.org/codecs.php
2000년 정도에 처음 영상처리 프로그래밍을 배울 때, 교수님은 Visual C++을 가지고 강의를 했었고, 나는 Java를 가지고 프로그래밍을 했다. (그 때 한참 Java에 빠져 있을 때여서, 모든 프로그래밍을 java로 했었다.)
이제 2017년에, Homomorphic Encryption 알고리즘으로 암호화된 상태의 지문 데이터에 대해 매칭을 해보고자 하려니, 다시 영상처리를 해야겠고(다 잊었다…ㅠ), 또한 C++을 이용해서 할 수밖에 없는 처지에 놓였다. (속도 땜에)
영상처리 기초부터 좀 봐야겠고, 해서 고른 책이 ‘열혈강의 – 영상 처리 프로그래밍’.
알고리즘 뿐만 아니라, 오랫만에 Visual Studio를 다뤄야 하는 나 같은 사람을 위해서인지, Visual Studio의 사용법, 잊었던 C++문법도 잘 설명해 주고 있다.
일단, 이 책을 추석 연휴를 이용해서 3~4일 봐서 끝냈고, 이 책에 소개된 이미미 처리용 기본 클래스들을 향후 테스트할 지문매칭 프로그래밍에 이용하기로 한다. 그리고, 내용 잊기전에 간단히 요약해 둔다.
목차 1. Visual Studio 설치 2. 열혈강의 책에서 소개된 소스코드 내려받기 3. Dialog를 이용한 이미지 출력
1. Visual Studio 설치
Visual Studio 2017 Community버전을 설치했다. 책에서는 Visual Studio 2012를 사용했는데, 2017로도 무방
– Visual Studio 2017을 설치하면, ‘MFC 응용 프로그램’용 프로젝트 만들기가 디폴트로 설치 안되어 있다. 이것은 추가로 설치해야 한다.
–> 파일메뉴-새로만들기-프로젝트 를 한 후, 왼쪽 하단부에 보면 “Visual Studio 설치관리자 열기” 있다. 클릭하고선, ‘개별 구성요소’ 탭을 선택한 후, ‘SDK, 라이브러리 및 프레임 워크’ 부분에 있는 ‘MFC 및 ALT 지원(x86 및 x64)’를 선택한 후 우측 하단부 ‘수정’버튼 클릭
– 그냥 C++코드만을 보는 용도로는 Visual Studio Code를 이용하고 있다. 탐색기에서 소스파일을 더블 클릭해서 읽을 때는, 굳이 무거운 Visual Studio를 사용하는 것보다, Editor역할만 하는 Visual Studio Code가 더 간편
2. 열혈강의 책에서 소개된 소스코드 내려받기
– 여기서 받을 수 있다. : www.freelec.co.kr – e카탈로그 – 도서 자료실
http://freelec.co.kr/bbs/read.asp?BBSName=BOOKPDS&page=1&id=206373
–> 밑에 나오는 예제만 돌려보려면, 여기에 있는 것 모두 다운받지 않고, 아래 쪽 글에서 언급된 파일들만 다운받으면 된다.
– 소스를 받으면 여러 프로젝트에 대한 소스가 있는데, 여기서 필요한 파일들만 압축파일로 만들었다.
(8_ColorEditor 프로젝트에 있는 imageSrc폴더내 파일들을 압축한 것임)
imageSrc.zip
3. Dialog를 이용해서, 이미지 출력해 보기
1)Visual Studio에서 프로젝트 만들기
– 파일메뉴 – 새로만들기 – 프로젝트에서, 아래 내용 입력 후 ‘확인’버튼 클릭
. 종류: MFC 응용 프로그램
. 이름: HelloImage
– ‘다음’ 누른 후, ‘응용 프로그램 종류’에서 “대화상자 기반” 선택하고, ‘마침’ 클릭
– 솔루션탐색기에서 ‘HelloImage’프로젝트 선택하고 우클릭 – 속성 – 일반 – 문자집합 : ‘멀티바이트 문자 집합’ 으로 선택
–> 이렇게 하지 않으면, 컴파일할 때 문자처리하는 곳에서 에러 발생함
2)영상처리용 라이브러리 파일 추가
– 탐색기에서, 위에서 만든 프로젝트가 있는 폴더로 이동 : …source/repos/HelloImage/HelloImage
– imageSrc 폴더 생성: …source/repos/HelloImage/HelloImage/imageSrc
– 다음 파일들을 imageSrc폴더에 paste (이 파일들은 위쪽에 있는 imageSrc.zip 안에 있다)
ImageFrameWnd.cpp
ImageFrameWnd.h
ImageFrameWndManager.cpp
ImageFrameWndManager.h
ImageView.cpp
ImageView.h
LoadImageFromFileDialog.cpp
LoadImageFromFileDialog.h
MyImage.h
3)영상처리용 라이브러리를 프로젝트에 추가
– Visual Studio의 ‘솔루션 탐색기’에서, ‘HelloImage’ 프로젝트 선택하고 마우스 우클릭 – 추가 – 새 필터
–> imageSrc 타이핑해서 새필터 생성
– imageSrc선택 후 마우스 우클릭 – 추가 – 기존 항목 : imageSrc폴더 밑에 있는 9개 파일 모두 선택 후 ‘추가’버튼 클릭
==> 이 처럼, 영상처리에 사용할 라이브러리를 imageSrc폴더에 넣고, 실제 코드에서는 헤더파일만 include한 후, 사용할 것임
4)다이얼로그에 이미지파일 읽어오기용 버튼 생성
-HelloImage 다이얼로그에다가 ‘영상 입력’버튼 생성: 도구상자에서 ‘버튼’ 선택 후, 다이얼로그 화면의 적당한 위치에 버튼 생성
– 버튼에 대한 속성 수정
. Caption: 영상 불러오기
. ID: IDC_BUTTON_LOAD_IMAGE
– 버튼클릭에 대한 이벤트 함수 만들기: ‘영상 불러오기’ 버튼을 더블 클릭
–> HelloImageDlg 클래스에, void CHelloImageDlg::OnBnClickedButtonLoadImage() 생성됨.
– HelloImageDlg파일의 상단부에, 이미지로드용 라이브러리 사용 위한 헤더파일 include 구문 추가
#include “imageSrc\LoadImageFromFileDialog.h”
#include “imageSrc\ImageFrameWndManager.h”
– void CHelloImageDlg::OnBnClickedButtonLoadImage() 함수를 아래와 같이 코딩
메서드 생성 됨. 이 메서드를 아래와 같이 코딩
void CHelloImageDlg::OnBnClickedButtonLoadImage() { CByteImage image = LoadImageFromDialog(); //LoadImageFromFileDialog.h if (image.IsEmpty()) return; ShowImage(image, “Hello~”); //ImageFrameWndManager.h }
프로그램을 실행시켜서 ‘영상 불러오기’ 버튼을 눌러 이미지 파일을 선택하면, 새로운 윈도우가 뜨면서 영상 출력될 것임
1. 이희석, 2013, 열혈강의-기초 알고리즘부터 라이브러리 활용까지-영상 처리 프로그래밍, 프리렉
– 끝-