C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[75096] Re:C 언어 구의 부피 관련 질문입니다.
빌더(TWx) [builder] 3567 읽음    2018-09-14 07:19
니시엔 님이 쓰신 글 :
: 우선 제가 하고자 하는것은 OpenCV를 통해 200,200 까만 IplImage를 생성 후 해당 이미지에 cvCircle를 통해 반지름 50인 흰색 원을 그린 후 해당 이미지를 통해 반지름 50인 구의 부피를 계산하려 합니다.
: 제가 생각하기엔 흰색인 이미지 한 Pixel 라인에서 Intensity 값이 255인 부분만 뽑아서  Pixel 개수가 지름인 원의 넓이를 모두 더하면 구의 부피가 될거라 생각했지만 실제 공식에 대입하여 계산한 값과 너무 많은 차이가 발생합니다.
: 왜 그런지 예상조차 되지 않아 여기에 도움을 청해봅니다.
: 실제 계산 소스(Test.bmp가 200,200 의 까만색 이미지에 반지름 50,중심좌표 100,100의 하얀 원을 그린 이미지 입니다.)
:
:         IplImage *src_Img = cvLoadImage("D:\\Test.bmp",0);
:    
:     int nRadius = 0;
:     double dData,dSize = 0;
:     std::vector<int> vector;
:     for(int i = 0;i<src_Img->height;i++){
:         for(int j =0;j<src_Img->widthStep;j++){
:             dData = (double)cvGetReal2D(src_Img,j,i);
:
:             if(dData == 255){
:                   nRadius++;
:             }
:             else if(dData != 255 && j>src_Img->widthStep/2){
:                 break;
:             }
:
:         }
:         if(nRadius != 0){
:             ListBox1->AddItem((UnicodeString)nRadius,NULL);
:             dSize += CalcSizeImage((double)nRadius);
:             nRadius = 0;
:         }
:     }
:    ShowMessage(dSize);
:
: 원 넓이 계산 함수.
:
:         double dRadius = dPixelData/2.0;
:
:     double dArea = dRadius * dRadius * M_PI;
:
:     return dArea;
:
: 실제 공식(M_PI 는 원주율)
:
:         double dSize = 4 / 3 * 50*50*50* M_PI;
:
:     ShowMessage(dSize);
:
: 공식으로 구한 구의 부피
: 392699.xxx
: 적분(?)으로 구한 구의 부피
: 522984.xxx
:



답변:


종이 위에 직사각형을 그렸다면 직사각형의 넓이는 (가로 * 세로) 이고 여기에 높이라는 개념은 존재하지 않죠.
원을 그렸다 해도 높이는 존재하지 않죠. 높이가 존재하려면 원이 아닌 원기둥이 되어야 하므로 정의가 완전히 다른거니.

구의 Volume(부피) 란 것이...

축구공을 0 에 무한히 가까운 두께로 얇게 썰어서 각각의 원넓이를 합해서(적분) 총합을 구한거라 극한 개념을 내포하고 있고
이 과정으로 유도된 식이 (4/3) * PI * pow(r, 3) 입니다.

여기서 4와 3과 PI는 상수로 볼 수 있고... 4 * PI / 3 의 상수 값 N 은 4.2 정도 입니다.

반지름 r = 1 부터 적용해 보면 pow(r, 3) 값은

pow(1,3) = 1
pow(2,3) = 8
pow(3,3) = 27
pow(4,3) = 64
.....

반지름 r 값이 1 증가 할 때 마다... 기하급수 적으로 증가하죠.
반지름 100일 때와 101 일때의 차이는 훨씬 더 큽니다.

거기다 위의 상수 N 값도 곱해주면 Volume 의 차이는 더 커집니다.

비트맵 이미지란 것은 실수좌표가 아니고 정수 좌표계라
동그란 원의 경우 오차가 몇 도트 씩은 나기 마련 입니다.



400 * 400 흑색 사각형 안에 반지름 100인 원이 그려져 있는 이미지.

// 샘플 이미지 생성.
	TBitmap* pBmp = new TBitmap;

	pBmp->Width = 400;
	pBmp->Height = 400;
    pBmp->PixelFormat = pf32bit;
	pBmp->Canvas->Brush->Color = clBlack;
	pBmp->Canvas->FloodFill(10, 10, clBlack, TFillStyle::fsBorder);
	pBmp->Canvas->Brush->Color = clWhite;
	pBmp->Canvas->Ellipse(100, 100, 300, 300);
	pBmp->SaveToFile("C:/test/test.bmp");
	delete pBmp;





bool Search(int* pData, int Size, int Value)
{
    for(int i = 0; i < Size; ++i) 
        if( pData[i] == Value ) return true;

    return false;
}

void __fastcall TForm3::Button3Click(TObject *Sender)
{
	TBitmap* pBmp = new TBitmap;
	pBmp->LoadFromFile("C:/test/test.bmp");

    TPixelFormat pf = pBmp->PixelFormat;
    assert(pf == pf32bit);

    int h1 = 0, h2 = 0;
    const float N = 4.0f * M_PI / 3.0f;

	for(int hT = 0, hB = pBmp->Height -1; hT < pBmp->Height && hB > 0; ++hT, --hB)
    {
        if( h1 == 0 && Search((int*)pBmp->ScanLine[hT], pBmp->Width, 0x00FFFFFF) )
            h1 = hT;

        if( h2 == 0 && Search((int*)pBmp->ScanLine[hB], pBmp->Width, 0x00FFFFFF) )
            h2 = hB;

        if( h1 && h2 ) {
            float r = abs( h1 - h2 ) / 2.0f;
            Memo1->Lines->Add( String().sprintf(L"r = %f, volume = %f", r, N * pow(r, 3.0f)) );
            break;
        }
    }
	delete pBmp;
}




2개의 루프 돌면서 총합을 더해가는 과정 밟을 필요 없이 (원넓이 오차누적)...
위의 코드와 같이 원의 반지름만 알아내서 한번에 계산하면 됍니다.

앞서 언급했듯이...
비트맵 자체가 근본적으로 정수좌표계라 깍두기 현상 때문에 원의 오차가 필연적으로 생길 수 밖에 없고

샘플 이미지의 경우에도 반지름을 100 으로 잡았지만 위와 같은 이유로 반지름이 98.5로 오차가 생깁니다.
비트맵 이미지를 아주 크게 그릴 수록 오차가 줄어 들겠지만... 기하급수 적인 상관관계 때문에 차이가 크게 발생할 수 밖에는.


반지름 100 으로 계산할 경우...

Volume = 4188790.20



정수좌표계의 오차로 인해 반지름이 98.5로 결정되었을 경우

Volume = 4003108.05



+ -

관련 글 리스트
75094 C 언어 구의 부피 관련 질문입니다. 니시엔 3257 2018/09/12
75096     Re:C 언어 구의 부피 관련 질문입니다. 빌더(TWx) 3567 2018/09/14
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.