자기개발/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);
	}

}

 

실행결과