자기개발/MFC
C++(MFC) - 이미지 회전(90,180,270), 상하좌우,색반전
pi92
2021. 9. 27. 13:08
이미지 프로세싱
CSize C_ReviewWnd::Plus90(OUT CSize& m_sizeImage)
{
//90도 회전시 가로와 세로 길이가 바뀌므로
CSize temp;
temp.cx = m_sizeImage.cy;
temp.cy = m_sizeImage.cx;
temp.cx -= temp.cx % 4; //세로길이가 가로가 되므로 4의 배수로 맞춰준다(90도회전, 270도회전)
SAFE_DELETES(m_pROI); // m_pROI : 변화된 이미지를 저장할 공간 초기화
int nSize = temp.cx * temp.cy;
m_pROI = new BYTE[nSize]{};
//이미지 픽셀 90도 회전시킨 픽셀을 m_pROI에 넣기
for (int i = 0; i < temp.cx; i++)
{
for (int j = 0; j < temp.cy; j++)
{
m_pROI[j * temp.cx + (temp.cx - 1 - i)] = m_pBits[i * m_sizeImage.cx + j];
}
}
return temp;
}
CSize C_ReviewWnd::Plus180(OUT CSize& m_sizeImage)
{
//180도 회전시 가로와 세로 길이가 같음
CSize temp = m_sizeImage;
SAFE_DELETES(m_pROI); // m_pROI : 변화된 이미지를 저장할 공간 초기화
int nSize = temp.cx * temp.cy;
m_pROI = new BYTE[nSize]{};
//이미지 픽셀 180도 회전시킨 픽셀을 m_pROI에 넣기
for (int i = 0; i < m_sizeImage.cy; i++)
{
for (int j = 0; j < m_sizeImage.cx; j++)
{
m_pROI[(m_sizeImage.cy - 1 - i) * m_sizeImage.cx + (m_sizeImage.cx - 1 - j)] = m_pBits[i * m_sizeImage.cx + j];
}
}
return temp;
}
CSize C_ReviewWnd::Plus270(OUT CSize& m_sizeImage)
{
//270도 회전시 가로와 세로 길이가 바뀌므로
CSize temp;
temp.cx = m_sizeImage.cy;
temp.cy = m_sizeImage.cx;
temp.cx -= temp.cx % 4; //세로길이가 가로가 되므로 4의 배수로 맞춰준다(90도회전, 270도회전)
SAFE_DELETES(m_pROI); // m_pROI : 변화된 이미지를 저장할 공간 초기화
int nSize = temp.cx * temp.cy;
m_pROI = new BYTE[nSize]{};
//이미지 픽셀 270도 회전시킨 픽셀을 m_pROI에 넣기
for (int i = 0; i < temp.cx; i++)
{
for (int j = 0; j < temp.cy; j++)
{
m_pROI[(temp.cy - 1 - j) * temp.cx + (i)] = m_pBits[i * m_sizeImage.cx + j];
}
}
return temp;
}
CSize C_ReviewWnd::Bottomtotop(OUT CSize& m_sizeImage)
{
//상하 반전시 가로와 세로 길이는 동일하다
CSize temp = m_sizeImage;
SAFE_DELETES(m_pROI); // m_pROI : 변화된 이미지를 저장할 공간 초기화
int nSize = temp.cx * temp.cy;
m_pROI = new BYTE[nSize]{};
//이미지 픽셀 상하 반전시킨 픽셀을 m_pROI에 넣기
//for (int i = 0; i < m_sizeImage.cy; i++)
//{
// for (int j = 0; j < m_sizeImage.cx; j++)
// {
// m_pROI[(m_sizeImage.cy - 1 - i) * m_sizeImage.cx + (j)] = m_pBits[i * m_sizeImage.cx + j];
// }
//}
//속도 개선
for (int i = 0; i < m_sizeImage.cy; i++) {
memcpy(m_pROI + (m_sizeImage.cy - 1 - i) * m_sizeImage.cx
, m_pBits + (i)*m_sizeImage.cx
, m_sizeImage.cx);
}
return temp;
}
CSize C_ReviewWnd::Lefttoright(OUT CSize& m_sizeImage)
{
//좌우 반전시 가로와 세로 길이는 동일하다
CSize temp = m_sizeImage;
SAFE_DELETES(m_pROI); // m_pROI : 변화된 이미지를 저장할 공간 초기화
int nSize = temp.cx * temp.cy;
m_pROI = new BYTE[nSize]{};
//이미지 픽셀 좌우 반전시킨 픽셀을 m_pChanged에 넣기
for (int i = 0; i < m_sizeImage.cy; i++)
{
for (int j = 0; j < m_sizeImage.cx; j++)
{
m_pROI[i * m_sizeImage.cx + (m_sizeImage.cx - 1 - j)] = m_pBits[i * m_sizeImage.cx + j];
}
}
return temp;
}
CSize C_ReviewWnd::Inverter(OUT CSize& m_sizeImage)
{
//이미지를 반전 시켰을 때 가로와 세로 길이는 동일하다
CSize temp = m_sizeImage;
SAFE_DELETES(m_pROI); // m_pROI : 변화된 이미지를 저장할 공간 초기화
int nSize = temp.cx * temp.cy;
m_pROI = new BYTE[nSize]{};
//이미지 픽셀값을 반전시켜서 m_pROI에 넣기
for (int i = 0; i < m_sizeImage.cy; i++)
{
for (int j = 0; j < m_sizeImage.cx; j++)
{
m_pROI[i * m_sizeImage.cx + j] = 255 - m_pBits[i * m_sizeImage.cx + j];
}
}
return temp;
}
LPBYTE C_ReviewWnd::Rocated(OUT CSize& sizeROI, int rocated)
{
sizeROI = m_sizeImage;
SAFE_DELETES(m_pROI); // m_pROI : 변화된 이미지를 저장할 공간 초기화
int nSize = m_sizeImage.cx * m_sizeImage.cy;
m_pROI = new BYTE[nSize]{};
int h = m_sizeImage.cy; // 세로 길이 저장
int w = m_sizeImage.cx; // 가로 길이 저장
int degree = rocated; // 회전 각도
int new_x, new_y;
int ValueofPixel;
int center_x = (m_sizeImage.cx / 2); // 회전 중심점
int center_y = (m_sizeImage.cy / 2); // 회전 중심점
//center_x = center_y = 0;
double seta = 3.14 / (180.0 / degree); // 라디안
//역방향 매핑
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++) {
new_x = (int)((x - center_x) * cos(seta) + (y - center_y) * sin(seta) + center_x);
new_y = (int)(-(x - center_x) * sin(seta) + (y - center_y) * cos(seta) + center_y);
if (new_x < 0 || (new_x >= w) || (new_y < 0) || (new_y >= h))
continue;
else
{
ValueofPixel = m_pBits[y * w + x];
}
m_pROI[new_y * w + new_x] = ValueofPixel;
new_x = 0; new_y = 0;
}
}
//정방향 매핑
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
new_x = (int)((x - center_x) * cos(seta) - (y - center_y) * sin(seta) + center_x);
new_y = (int)((x - center_x) * sin(seta) + (y - center_y) * cos(seta) + center_y);
if ((new_x < 0) || (new_x >= w) || (new_y < 0) || (new_y >= h))
//이미지 범위를 벗어나면 0 값
{
ValueofPixel = 0;
}
else
{
ValueofPixel = m_pBits[new_y * w + new_x];
}
m_pROI[y * w + x] = ValueofPixel;
new_x = 0; new_y = 0;
}
}
rect_flag = false;
return m_pROI;
}
참고
LPBYTE C_ReviewWnd::DrawImage(OUT CSize& sizeROI, int choice)
{
switch (choice) {
case 1:
sizeROI = Plus90(m_sizeImage); //90도 회전
break;
case 2:
sizeROI = Plus180(m_sizeImage); // 180도 회전
break;
case 3:
sizeROI = Plus270(m_sizeImage); // 270도 회전
break;
case 4:
sizeROI = Bottomtotop(m_sizeImage); //상하 반전
break;
case 5:
sizeROI = Lefttoright(m_sizeImage); // 좌우 반전
break;
case 6:
sizeROI = Inverter(m_sizeImage); // 색반전
break;
default:
break;
}
rect_flag = false;
Invalidate();
return m_pROI;
}
void CMFCImageTestDlg::OnBnClickedButtonPlus90()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
LPBYTE pBits = m_stcImage.DrawImage(sizeROI, 1); // 뒤에 숫자 1은 Plus90을 의미
// m_stcROI에 ROI 이미지를 보여준다.
if (pBits) {
m_stcROI.LoadImageData(pBits, sizeROI);
}
}
void CMFCImageTestDlg::OnBnClickedButtonPlus180()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
LPBYTE pBits = m_stcImage.DrawImage(sizeROI, 2); // 뒤에 숫자 2는 Plus180을 의미
// m_stcROI에 ROI 이미지를 보여준다.
if (pBits) {
m_stcROI.LoadImageData(pBits, sizeROI);
}
}
void CMFCImageTestDlg::OnBnClickedButtonPlus270()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
LPBYTE pBits = m_stcImage.DrawImage(sizeROI, 3); // 뒤에 숫자 3은 Plus270을 의미
// m_stcROI에 ROI 이미지를 보여준다.
if (pBits) {
m_stcROI.LoadImageData(pBits, sizeROI);
}
}
void CMFCImageTestDlg::OnBnClickedButtonBottomtotop()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
LPBYTE pBits = m_stcImage.DrawImage(sizeROI, 4); // 뒤에 숫자 4는 Bottomtotop을 의미
// m_stcROI에 ROI 이미지를 보여준다.
if (pBits) {
m_stcROI.LoadImageData(pBits, sizeROI);
}
}
void CMFCImageTestDlg::OnBnClickedButtonLefttoright()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
LPBYTE pBits = m_stcImage.DrawImage(sizeROI, 5); // 뒤에 숫자 5는 Lefttoright을 의미
// m_stcROI에 ROI 이미지를 보여준다.
if (pBits) {
m_stcROI.LoadImageData(pBits, sizeROI);
}
}
void CMFCImageTestDlg::OnBnClickedButtonInverter()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
LPBYTE pBits = m_stcImage.DrawImage(sizeROI, 6); // 뒤에 숫자 6은 Inverter을 의미
// m_stcROI에 ROI 이미지를 보여준다.
if (pBits) {
m_stcROI.LoadImageData(pBits, sizeROI);
}
}
void CMFCImageTestDlg::OnBnClickedButtonRocated()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
//입력한 각도 가져오기
CString t_rocated = _T("");
m_edit_rocated.GetWindowTextW(t_rocated);
//CString to int
int n_rocated;
n_rocated = _ttoi(t_rocated);
sizeROI;
LPBYTE pBits = m_stcImage.Rocated(sizeROI, n_rocated);
// m_stcROI에 ROI 이미지를 보여준다.
if (pBits) {
m_stcROI.LoadImageData(pBits, sizeROI);
}
}
실행결과