Crazybit 개발 수기 (1): 디자인 의 데이터 구조 와 알고리즘 분리
Crazybit
홈 페이지:
www.crazy-bit.com
개발 수 기 는 제 가 PhoXo (작고 32bit 이미지 처리 소프트웨어) 를 개발 하 는 과정 에서 느 낀 점 을 기 록 했 습 니 다. 모두 실제 응용 에서 비롯 되 었 고 제 가 OO (object orient) 를 탐색 하 는 길에 얻 은 전리품 입 니 다. 여러분 께 도움 이 되 기 를 바 랍 니 다.windows 에서 프로그램 을 만 든 모든 사람들 이 비트 맵 을 사용 한 적 이 있다 고 믿 습 니 다. 대부분 사람들 은 인터넷 에서 성숙 하고 완 선 된 DIB 라 이브 러 리 를 다운로드 하여 사용 합 니 다 (예 를 들 어 CxImage, CDIB). 소수의 사람들 은 자신 이 봉 인 된 DIB 라 이브 러 리 를 가지 고 있어 서 앞으로 의 확장 과 사용 에 편리 합 니 다.(최근 몇 년 동안 GDI + 이 군 돌기, 예 를 들 어 확대, 회전, 그 라 데 이 션 충전 등 은 비 길 데 없 는 속도 와 품질 을 제공 하지만 완벽 한 이미지 처리 프로그램 을 만 들 려 면 구조 디자인 에 어려움 을 가 져 올 수 있 습 니 다. adapter 모드 로 포장 한 후에 사용 할 수 있 습 니 다. 멀리 떨 어 졌 습 니 다)
이 럴 때 그림 처리 작업 이 필요 하 다 면 어떻게 하 시 겠 습 니까?OO 경험 이 없 는 C + + 프로그래머 (예 를 들 어 1 년 전 나) 들 이 이렇게 할 수 있 습 니 다. 클래스 에 직접 방법 을 추가 할 수 있 습 니 다.
4. 567913. 여기 서 두 가지 예 (각각 반 색, RGB 값 조절 기능 실현) 를 들 었 습 니 다. 현실 에서 대량의 이런 조작 이 있 을 것 입 니 다. 밝기, 대비 도, 포화 도....................................................첫 번 째 단 계 는 반드시 위 에서 코드 를 복사 한 후에 그 중의 인터페이스 와 처리 부분 을 고 치 는 것 이다.이곳 의 시범 코드 는 매우 짧 아서 bug 와 함께 복사 되 지 는 않 지만 시한폭탄 은 하나 더 생 겼 다.어느 날, 당신 의 boss 가 당신 에 게 말 합 니 다: 나 는 장시간 의 기다 림 을 참 을 수 없습니다. 나 에 게 진도 표를 추가 해 주세요.전체 변 수 를 추가 할 수도 있 습 니 다. 모든 함수 에 인 자 를 추가 할 수도 있 습 니 다. 그러나 변 하지 않 는 것 은 모든 처리 함수 의 코드 를 수정 해 야 합 니 다. 마음의 저주 가 그 중의 어떤 것 도 바 꾸 지 않 습 니 다.이때 bug 는 옆에서 기 회 를 엿 보고 움 직 였 습 니 다. 그러나 힘 든 날 은 아직 끝나 지 않 았 습 니 다. 한 달 후에 당신 의 심혈 을 기울 인 사장 은 그 중에서 지역 처리 기능 을 추가 하고 한 달 후에...
나중에 코드 다시 볼 까요?맞아요. 빨간색 코드 를 제외 하고 다른 곳 에서 만 져 보면 이 알고리즘 들 을 분리 해서 뽑 을 수 있 을까요?아마도 우 리 는 곧 표준 라 이브 러 리 에서 qsort 와 windows 에서 자주 사용 하 는 리 셋 방법 을 생각 할 것 이다.좋아, 우리 가 실제로 해 보 자.
//================================================================
int FClamp0255 (int nValue) {return max (0, min (0xFF, nValue));} // 0--255
class FCObjImage
{
public :
Invert () ;
AdjustRGB (int R, int G, int B) ;
} ;
//================================================================
void FCObjImage::Invert ()
{
if ((GetHandle() == NULL) || (ColorBits() < 24))
return ;
int nSpan = ColorBits() / 8 ; // 3, 4
for (int y=0 ; y < Height() ; y++)
{
BYTE * pPixel = GetBits (y) ;
for (int x=0 ; x < Width() ; x++, pPixel += nSpan)
{
pPixel[0] = ~pPixel[0] ;
pPixel[1] = ~pPixel[1] ;
pPixel[2] = ~pPixel[2] ;
}
}
}
//================================================================
void FCObjImage::AdjustRGB (int R, int G, int B)
{
if ((GetHandle() == NULL) || (ColorBits() < 24))
return ;
int nSpan = ColorBits() / 8 ; // 3, 4
for (int y=0 ; y < Height() ; y++)
{
BYTE * pPixel = GetBits (y) ;
for (int x=0 ; x < Width() ; x++, pPixel += nSpan)
{
pPixel[0] = FClamp0255 (pPixel[0] + B) ;
pPixel[1] = FClamp0255 (pPixel[1] + G) ;
pPixel[2] = FClamp0255 (pPixel[2] + R) ;
}
}
}
//================================================================
응, 괜 찮 은 것 같 아. 알고리즘 이 단일 함수 에서 벗 겨 져 서 우 리 는 이미 문 제 를 해결 한 것 같 아.Invert 를 처리 하 는 것 은 아주 잘 되 었 지만 AdjustRGB 를 처리 하 는 데 어려움 을 겪 었 습 니 다. RGB 의 세 가지 조절 매개 변 수 는 어떻게 전달 되 나 요?우리 의 인터페이스 매개 변 수 는 하나 뿐 입 니 다. 전역 변수 / 구성원 변 수 를 추가 하 시 겠 습 니까?이것 은 방법 이지 만 이런 방법 이 증가 함 에 따라 프로그램의 가 독성 과 유지 성 이 급 격 히 떨 어 지고 오히려 이전의 효 과 를 바 꾸 는 것 이 좋다.그렇다면 어떻게 고도 의 추상 과 좋 은 인 터 페 이 스 를 실현 합 니까?저희 가 현장에서 OO (object orient) 를 모 시 겠 습 니 다. 그것 의 실현 에 대해 말씀 해 주 십시오.다음 과 같은 파생 관 계 를 설계 합 니 다.
//================================================================
void Pixel_Invert (BYTE * pPixel)
{
pPixel[0] = ~pPixel[0] ;
pPixel[1] = ~pPixel[1] ;
pPixel[2] = ~pPixel[2] ;
}
//================================================================
void FCObjImage::PixelProcess (void(__cdecl*PixelProc)(BYTE * pPixel))
{
if ((GetHandle() == NULL) || (ColorBits() < 24))
return ;
int nSpan = ColorBits() / 8 ; // 3, 4
for (int y=0 ; y < Height() ; y++)
{
BYTE * pPixel = GetBits (y) ;
for (int x=0 ; x < Width() ; x++, pPixel += nSpan)
{
(*PixelProc) (pPixel) ;
}
}
}
//================================================================
void FCObjImage::Invert ()
{
PixelProcess (Pixel_Invert) ;
}
//================================================================
그리고 우 리 는 이미지 클래스 를 다음 과 같이 수정 합 니 다.
//================================================================
class FCSinglePixelProcessBase
{
public :
virtual void ProcessPixel (int x, int y, BYTE * pPixel) PURE ;
} ;
//================================================================
class FCPixelInvert : public FCSinglePixelProcessBase
{
public :
virtual void ProcessPixel (int x, int y, BYTE * pPixel) ;
} ;
void FCPixelInvert::ProcessPixel (int x, int y, BYTE * pPixel)
{
pPixel[0] = ~pPixel[0] ; pPixel[1] = ~pPixel[1] ; pPixel[2] = ~pPixel[2] ;
}
//================================================================
class FCPixelAdjustRGB : public FCSinglePixelProcessBase
{
public :
FCPixelAdjustRGB (int DeltaR, int DeltaG, int DeltaB) ;
virtual void ProcessPixel (int x, int y, BYTE * pPixel) ;
protected :
int m_iDeltaR, m_iDeltaG, m_iDeltaB ;
} ;
void FCPixelAdjustRGB::ProcessPixel (int x, int y, BYTE * pPixel)
{
pPixel[0] = FClamp0255 (pPixel[0] + m_iDeltaB) ;
pPixel[1] = FClamp0255 (pPixel[1] + m_iDeltaG) ;
pPixel[2] = FClamp0255 (pPixel[2] + m_iDeltaR) ;
}
//================================================================
(이상 은 기본 프레임 워 크 입 니 다. 지역 처리 파 라 메 터 를 쉽게 추가 할 수 있 습 니 다. 구 조 를 통 해 RECT 파 라 메 터 를 전달 할 수 있 습 니 다.) 대상 은 정말 기묘 한 것 입 니 다. 대외 적 으로 간단 한 인 터 페 이 스 를 제공 할 수 있 고 자신 은 많은 추가 정 보 를 밀봉 할 수 있 습 니 다.자, 이제 방금 의 성 과 를 검증 해 보 겠 습 니 다. 그림 의 홀수 줄 에 검은색 을 두 고 짝수 줄 에 흰색 을 두 는 작업 을 추가 합 니 다.
4. 567913. 얼마나 조 화 롭 고 아름 다운 지, 알고리즘 을 디자인 하 는 사람 은 자신의 알고리즘 만 쓰 고 진도 와 지역 등 문 제 를 어떻게 지원 하 는 지 고려 하지 않 아 도 된다.디자인 이 좋 은 AK 처럼 끊임없이 총알 (대상) 을 넣 을 수 있 습 니 다 ^ - ^
이로써 우 리 는 이미 큰 성 과 를 거 두 었 을 것 이다.
또 질문 있어 요?
잠깐 만, 서 두 르 지 마. 어떤 부분 은 잘 안 맞 아. 내 가 이 알고리즘 을 추가 한 후에 어떻게 이렇게 오래 컴 파일 했 지?
문 제 는 바로 그 보 잘 것 없 는 것 이다. \ # include "PixelProcessor. h" image 는 이미지 처리 의 최 하층 대상 이 고 프로젝트 의 모든 파일 이 직접적 이거 나 간접 적 으로 포함 되 어 있 기 때문에 image. h 자체 와 그 에 포 함 된. h 의 수정 은 거의 모든 공정 의 build 를 야기 할 것 이다. 이것 은 당연히 참 을 수 없다. 해결 방법 은 '사전 성명' 을 사용 하 는 것 이다.PixelHandler 인터페이스 에서 우 리 는 그것 의 인용 만 필요 하기 때문이다.
그래서 우 리 는 \ # include "PixelProcessor. h" 를 class FCSinglePixelProcessBase 로 교체 합 니 다. /external class 사전 성명 을 한 다음 에. cpp 파일 에 PixelProcessor. h 를 포함 하면 PixelProcessor. h 에 대한 변 화 는. cpp 파일 의 재 컴 파일 만 초래 하고 컴 파일 시간 을 크게 절약 할 수 있 습 니 다.결론: 1) 가능 하 다 면 프로 그래 밍 에서 '코드 복사' 라 는 단 어 를 영원히 생각 하지 마 세 요.OO 는 추상 과 코드 재 활용 을 위해 탄생 한 것 이다.2) 필요 하지 않 으 면 클래스 의 구성원 변수 와 함수 의 인 자 는 포인터 나 인용 으로 대체 할 수 있 습 니 다. 이렇게 하면. h 에 다른. h 파일 을 최대한 적 게 포함 하고 사전 성명 으로 대체 하여 컴 파일 시간 과 앞으로 발생 할 수 있 는 교차 포함 을 줄 일 수 있 습 니 다.3) 마지막 으로 효율 문 제 를 말한다. 어떤 친구 들 은 픽 셀 마다 가상 함 수 를 호출 하면 성능 에 영향 을 줄 수 있다 고 말 할 수 있 지만 실제 손실 은 상상 보다 크 지 않다.제 가 실측 해 봤 습 니 다. 1024 * 768 의 사진 에 대해 반 편 처 리 를 했 습 니 다. 속 도 는 5% 정도 의 손실 만 있 고 복잡 한 처리 (밝기 / 대비 도 / gamma) 를 할 때 손실 은 완전히 무시 할 수 있 습 니 다. 왜냐하면 많은 코드 는 스 택 에 들 어가 고 표 시 를 검사 하 는 것 일 뿐 부동 소수점 에서 이런 시간 을 소모 하 는 명령 을 제외 하 는 것 이 아 닙 니 다.
[Summary]
실제 전체 재 구성 과정 은 디자인 모델 과 유사 한 전략 모델 이다. 사실 stl 의 분리 사상 과 매우 유사 하 다.
... 에 있다http://www.crazy-bit.com/ 좋 은 오픈 소스 이미지 처리 라 이브 러 리 ImageStone V 4.0 (이미지 파일 읽 기와 쓰기, 많은 이미지 변환 및 이미지 디 스 플레이 포함)
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.