차영상을 만들려면 일단 영상 두개에 차이가 있어야 하는데,

하나의 동영상으로 프레임 순서의 차이를 두고 그에 따른 차이를 영상으로 표현할려고 합니다.

영상들 정의

    previous_image =  cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    current_image =  cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    output =  cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    diff_image = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);

이렇게 되어있고

작업을 통해 output  영상을 이진화 작업을 해 놓았습니다.

그런후

        cvCopy(current_image,previous_image);
        cvCopy(output,current_image);
        cvAbsDiff(previous_image,current_image, diff_image);

를 통하여 diff_image 에 차영상을 만들었습니다.



접근 및 제어 방법

ex)
for (int i = 0; i < img->height;i++)
        {
            for (int j = 0; j < img->width;j++)
            {
                // 데이터 직접 접근 /제어
                int index = j + i * img->widthStep ;
                unsigned char n_indx = gray->imageData[index] ;      // 해당 픽셀에 접근하여 n_indx 에 픽셀값 저장

     if(n_indx < 100)   //픽셀 값이 100보다 작을경우
                {
                    img->imageData[j+i*(img->widthStep)] = 0;         // img의 픽셀 값을 제어
                }
            }
        }





 




출처 -> www.codein.co.kr  프로그래머의 놀이터 (Code人)

 

MFC의 직렬화(Serialize)를 사용해, 오브젝트을 파일에 쓰고 읽는 방법에 대해 살펴보겠습니다.


소개할 기능은 기본적으로, 오브젝트의 현재 상태를 파일에 보존하거나 복원 하는 기능입니다.

 

1) MFC AppWizard를 사용해, 다이얼로그 기반의 프로젝트를 작성합니다.
메인 다이얼로그에 아래와 같이 컨트롤을 배치합니다.


(여기에서는, 프로젝트명을 Serialize Test 로서 작성했습니다.)

사용자 삽입 이미지

2) 새로운 클래스를 생성합니다.

클래스타입은 "Generic Class", 클래스명은 "CNewData" 이고, 부모클래스로 "CObject"를 지정합니다.

OK 버튼을 클릭해서, 클래스를 생성합니다.

사용자 삽입 이미지

 

// MyData.h

class CMyData : public CObject 
{
    DECLARE_SERIAL( CMyData)    // 직렬화 선언
public:
    CMyData();
    virtual ~CMyData();

    // 다음함수(Serialize)를 오버라이딩
    virtual void Serialize( CArchive& archive );

    int m_nValue;        // 값1: 다이얼로그의 "IDC_EDIT1"에 해당
    CString m_strValue;  // 값2: 다이얼로그의 "IDC_EDIT2"에 해당
};

 

// MyData.cpp
#include "stdafx.h"
#include "SerializeTest.h"
#include "MyData.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// 직렬화선언

IMPLEMENT_SERIAL( CMyData, CObject, 1)
////////////////////////////////////////////////////////
// Construction/Destruction

////////////////////////////////////////////////////////

CMyData::CMyData()
{
   //멤버변수 초기화

    m_nValue = 0;
}

CMyData::~CMyData()
{

}

// Serialize 함수를 오버라이딩(재정의)
void CMyData::Serialize( CArchive& ar)
{
    // 부모클래스의 함수를 호출
    CObject::Serialize( ar);


    // 이클래스의 데이터를 보존
    if( ar.IsLoading() == TRUE)
    {
        // 읽어올때
        ar >> m_nValue >> m_strValue;
    }
    else
    {
        // 저장할때
        ar << m_nValue << m_strValue;
    }
}

다이얼로그 내용의 저장, 읽어오기 버튼의 클릭 이벤트 핸들러를 작성합니다.
(다이얼로그의 버튼상에서 더블 클릭)
아래와 같은 내용을 기술합니다.

 

// MyData.cpp: 
//
///////////////////////////////////////////////////////
#include "MyData.h"

// 저장버튼 클릭시

void CSerializeTestDlg::OnButton1() 
{
    // TODO:

    BOOL bret;
    // 화면에 입력된 내용을 읽어서, 파일에 저장

    CMyData data;
    int nValue;
    CString strValue;


    // 값1은、int형으로 보존
    nValue = (int)GetDlgItemInt( IDC_EDIT1);
    GetDlgItemText( IDC_EDIT2, strValue);

    data.m_nValue = nValue;
    data.m_strValue = strValue;

   

    // 파일을 쓰기모드로 오픈

    CFile f;
    bret = f.Open( "C:\\Temp\\MyData.dat", 
            CFile::modeCreate | CFile::modeWrite);
    if( bret == FALSE)
    {
        AfxMessageBox( "파일열기 실패");
        return;
    }


    CArchive ar( &f, CArchive::store);
    TRY
    {
        data.Serialize( ar);
    }
    CATCH_ALL( e)
    {
        AfxMessageBox( "보존에러");
    }
    END_CATCH_ALL;

   

   ar.Close();
    f.Close();

    // 화면내용을 초기화

    SetDlgItemText( IDC_EDIT1, "");
    SetDlgItemText( IDC_EDIT2, "");

}


// 읽어오기 버튼 클릭시
void CSerializeTestDlg::OnButton2() 
{
    // TODO:

    // 파일을 엽니다.
    BOOL bret;
    CFile f;
    bret = f.Open( "C:\\Temp\\MyData.dat", CFile::modeRead);
    if( bret == FALSE)
    {
        AfxMessageBox( "파일열기 실패");
        return;
    }

    CMyData data;

    CArchive ar( &f, CArchive::load);
    TRY
    {
        data.Serialize( ar);
    }
    CATCH_ALL( e)
    {
        AfxMessageBox( "보존에러");
    }
    END_CATCH_ALL;

 

   ar.Close();
    f.Close();

    // 화면에 출력

    SetDlgItemInt( IDC_EDIT1, data.m_nValue);
    SetDlgItemText( IDC_EDIT2, data.m_strValue);

}

 

정리하면,

1) 화면의 내용을 읽어와서 CMyData의 멤버변수에 저장합니다. 그리고, CMyData 객체의 내용(멤버변수)을 파일에 저장합니다.

2) 파일을 열어서 저장된 내용을 가져온후, 이를 CMyData 객체의 내용으로 채웁니다

<script language="javascript" type="text/javascript">
<!--
   function save() {
      opener.location.replace('부모장.asp,jsp,php');
      window.close();
 }
-->
</script>

...

<a href="#" onclick="save();">닫기</a>

 

 부모창에서 새 창을 연 뒤 코드를 수행하고 마지막으로 새 창을 닫으면서 부모창을 새로 불러오는 것이다.

새창에서 어떤 값들이 변경되고 DB에 저장이 된 후에 부모창에서 변경된 값을 반영해야 할 때 쓰면 유용하다.

아마 문제가 있다면 부모창에 검색결과가 나오고, 그 뒤에 새 창을 열었다면 아마 위의 코드로는
부모창의 검색결과가 보여지는 것이 아니라, 검색 전의 초기화면이 보여질 것이다.


지식인 QnA 펌

 

질문

decoding.exe의 0x00413f9d에 처리되지 않은 예외가 있습니다. 0xC0000005: 0x00000000 위치를 기록하는 동안 액세스 위반이 발생했습니다. 엑세스 위반이라는 것으로 실행이 안되는데요.

0x00413f9d 라는 부분은 어떻게 해석을 해야 할지와 엑세스 위반이라는 것은 무엇인지

답변 부탁드리겠습니다~(__) 

 

답변

엑세스 위반(Access Violation)은, 프로세스가 접근할 권한이 없는 메모리 영역에 접근하고자 했을 때 발생합니다.

 

윈도우는 메모리의 모든 영역을 가상메모리 페이지 단위로 관리하는데, 이 메모리 영역마다 접근 권한을 설정합니다. 이 권한은 프로세스가 가진 속성별로 관리됩니다. 크게 사용자가 만든 사용자 프로세스와, 윈도우 시스템에서 돌리는 커널 프로세스로 구분할 수 있죠. 윈도우에서 관리하는 메모리는 커널에서만 읽고 쓸수 있는 영억, 커널에서만 읽을 수 있는 영억,  사용자프로세스에서도 읽을 수 있는 영역, 사용자 프로세스가 읽고 쓸 수 있는 영역 등으로, 가상메모리 페이지에 권한이 설정되어 있습니다.

따라서 적절한 권한이 없는 프로세스가 제한된 메모리 영역에 읽고 쓰기를 시도할 때 엑세스 위반이 발생합니다. 대표적인 예로 "0xC0000005: 0x00000000 위치를 기록하는 동안 엑세스 위반이 발생했습니다"라는 예외는 0x00000000 번지, 즉 널 포인터에 대하여 쓰기를 시도했다는 뜻이죠. 0x00000000번지로 시작하는 메모리 영역은 유저 프로세스에 대해서는 읽기/쓰기가 금지된 영역입니다. 시스템 운영에 중요한 정보가 기록되어 있기 때문이죠. 따라서 사용자가 만든 프로그램이 이 위치를 접근하고자 하는 것은 이와 같은 에러를 냅니다.

에러 메시지에서, "decoding.exe의 0x00413f9d에 처리되지 않은 예외가 있습니다. 0xC0000005: 0x00000000 위치를 기록하는 동안 액세스 위반이 발생했습니다."의 0x00413f9d는, 0x00000000위치를 접근하고자 하는 명령이 수행된, 명령이 저장된 번지수입니다. 디버깅할 때 해당 번지수의 명령이 무엇인가를 살펴보면 비교적 헤메지 않고 버그를 잡을 수 있습니다.

 

답변

이런 경우는 대부분..

메모리 할당이 되지 않은 포인터(NULL Pointer)에 값을 넣었거나..

할당치를 초과하여 데이터가 입력되었을 때입니다..

 

답변

0x00413f9d 는 decoding.exe 이란 프로그램의 code 영역 주소입니다.

즉 decoding.exe의 0x00413f9d 주소에서 예외처리가 발생했다는것입니다.

프로그램은 대부분 0x00400000이 시작번지이므로

offset 0x00013f9d에서 0xc0000005 에러가 발생했다는것입니다.

 

답변

0x00413f9d는 메모리의 주소를 말하는 것으로, 동적 메모리를 할당하지 않았거나

할당항 메모리를 넘어서 접근 할 경우에 이러한 에러가 나게 됩니다.

 

int *temp;

temp[0] = 10; // 메모리 에러(할당하지 않고 사용한 경우)

 

int *temp1;

temp1 = new int [10];

temp1[15] = 10; //메모리 에러(할당은 하였지만 할당항 메모리를 넘어서 사용한 경우)

 


1. cvMemStorage 구조체에 대해 알아보자.

typedef struct CvMemStorage
{
    int signature;
    CvMemBlock* bottom;              /* First allocated block.                   */
    CvMemBlock* top;                   /* Current memory block - top of the stack. */
    struct  CvMemStorage* parent; /* We get new blocks from parent as needed. */
    int block_size;                        /* Block size.                              */
    int free_space;                       /* Remaining free space in current block.   */
}
CvMemStorage;


typedef struct CvMemBlock
{
    struct CvMemBlock*  prev;
    struct CvMemBlock*  next;
}
CvMemBlock;

2. deque

Deque = Double Ended Queue

우리말로 읽을때 발을을 "데크"라 발음한다.

Deque는 와 매우 유사하다.  데이터를 일렬로 저장하게 되며, 각 데이터에 대한 임의 접근이 가능하다. 연속적인 데이터의 끝에 요소를 추가하거나 삭제 하는 것은 constance time 즉 O(1) 이 걸린다. 또한 요소들의 중간에 데이터를 삽입하거나 삭제할 경우 linear time 즉 O(n) 의 time complexity 를 갖는다.

Deque 가 vector와 다른 가장 큰 이유는, deque는 sequence 즉 데이터들의 앞쪽에 데이터를 추가하거나 삭제하는데 있어서 constant time O(1)의 시간이 걸린다는 것이다. (*참고적으로 vector는 앞쪽에 데이터를 추가/삭재에 있어서 O(n) 의 시간이 걸린다).


3.cvFindContours - 외곽선생성

int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int header_size=sizeof(CvContour), int mode=CV_RETR_LIST, int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );

 

  • 외부 Contour: 흑=>백
  • 내부 Contour: 백=>흑
image source이미지. 8-bit 1-channel.
Gray 영상도 가능(non-zero: 1, zero: 0으로 간주함).

주. 함수의 수행 과정에서 원본 이미지를 변경시킴.
storage 찾아진 contour들을 저장할 container
first_contour 결과 매개변수. 첫 번째 외부 contour의 포인터 저장
header_size 결과는 CvSeq에 저장되는데 이 때 저장될 자료구조의 크기.
- method가 CV_CHAIN_CODE이면 >= sizeof(CvChain)
- 그렇지 않으면 >= sizeof(CvContour)
mode 추출 방법
- CV_RETR_EXTERNAL: 최외부 contour만 추출
- CV_RETR_LIST: 모든 contour를 찾아 한 list에 저장 (hierachycal 구조가 아님)
- CV_RETR_CCOMP: 모든 contour를 찾아 2-level 트리 구조로 구성. top 레벨은 외부 contour, second 레벨은 내부contour(holes)
- CV_RETR_TREE: 모든 contour를 찾아 full hierachy 트리 구조 구성
- CV_RETR_RUNS: Run-type 방법으로 추출하는 듯. 자세히는 모르겠음.
method Approximation 방법 (CV_RETR_RUNS는 자체 방법을 사용하므로 이를 제외한 모든 방법에서만 사용함)
- CV_CHAIN_CODE: the Freeman chain code로 저장됨. (이걸 제외하고 나머지 method는 polygon 구조(sequences of vertices)로 저장함.
- CV_CHAIN_APPROX_NONE: 단순히 chain code를 point 구조로 변경함
- CV_CHAIN_APPROX_SIMPLE: 수평, 수직, 대각선 성분을 압축. ending point들만 남겨둠.
- CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPROX_TC89_KCOS: Teh-Chin chain approximation 알고리즘으로 압축
- CV_LINK_RUNS: CV_RETR_LIST 모드에서만 사용됨. 자세히는 모르겠음.
offset contour 포인트들이 shift될 값 ROI 설정한 경우 좋음.
 
 

cvFindContours 함수는 이미지에서 contour를 찾은 후 contour의 갯수를 리턴

원형
int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq* first_contour,
                            int header_size=sizeof(CvContour), int mode, int mthod, CvPoint offset=cvPoint(0,0) );

패러미터
- image : 8비트 grayscale 영상만을 패러미터로 넘길 수 있다. 0이 아닌 픽셀은 1로, 0인 픽셀은 0으로 간주하여 자체적으로 2진 영상으로 처리하게 된다.

- storage : CvMemStorage 구조체의 포인터를 넘긴다. 실제로 contour 정보가 저장되는 공간이다.

- first_contour : 첫번째 최외곽 contour의 정보를 저장할 CvSeq 구조체의 포인터

- header_size : 시퀀스 헤더의 크기  ex) sizeof(CvContour)

- mode :  contour 검출 방법
  CV_RETR_EXTERNAL - 오직 최외곽 contour만을 검출한다.
  CV_RETR_LIST - 모든 contour를 검출하여 list로 저장한다.
  CV_RETR_CCOMP - 모든 contour를 검출한 후 2단계로 계층화한다.
                              상위 계층은 각 성분(component)의 외곽 경계를 나타내며 하위 계층은 성분 내부의
                              구멍(hole)을 나타낸다.
  CV_RETR_TREE - 모든 contour를 검출한 후 각 contour를 tree 형태로 구조화한다.

- moethod : approximation(생략산) 방법이다.
생략산이란 불필요한 연산량을 줄이기 위하여 모든 contour를 구하지 않고 추정
  CV_CHAIN_CODE - Freeman chain code를 사용하여 contour를 출력한다. 이것 외의 다른 모든 방법은
                            결과물을 polygon(다각형, 버텍스의 나열)로 출력한다.
  CV_CHAIN_APPROX_NONE - 모든 contour의 점을 chain code에서 point로 변환한다.
  CV_CHAIN_APPROX_SIMPLE - 가로, 세로, 대각선 으로 쪼개서 압축하며 함수는 끝점만을 출력한다.
  CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPROX_TC89_KCOS - Teh-Chin chain approximation
                                                                                              알고리즘에 사용된다.
  CV_LINK_RUNS - 1의 수평 구획의 연결을 통해 완전히 다른 방식의 contour 검출 알고리즘을 사용한다.  
  CV_RETR_LIST 모드에서만 사용 가능하다.

- offset : 모든 contour 포인트 이동
 
예제

CvMemStorage* storage = cvCreateStorage(0); // 배열 자료형 : 점의 좌표가 들어감
CvSeq* seq = NULL; //경계 개수를 저장할 변수 선언
int numContour = cvFindContours(src, storage, &seq, sizeof(CvContour), CV_RETR_TREE,   
                                             CV_CHAIN_APPROX_SIMPLE);

[출처] cvFindContours|작성자 천재소년







// Visual Studio 2008 , OpenCV 2.1


#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>

int _tmain(int argc, _TCHAR* argv[])
{

 CvCapture* capture = NULL;
 IplImage * frame = 0;
 IplImage * frame_copy = 0;

 capture = cvCaptureFromFile("sample.avi");
 cvNamedWindow("reuslt", 1);

 for(;;)
 {

  if (!cvGrabFrame(capture))

   break;

  frame = cvRetrieveFrame(capture);
  if (!frame)

   break;

  cvShowImage("result", frame);
  if (cvWaitKey(33) >= 0)

   break;

 }

 cvReleaseImage(&frame_copy);
 cvReleaseCapture(&capture);
}

출처 : http://www.sensibleui.co.kr/7


image_thumb6이전 포스트에서 OpenCV 2.0과 Visual Studio 2008의 연동에 관한 글을 올렸습니다. 그런데 확인을 해보니OpenCV의 새 버전 2.1이 4월에 나왔더군요. 거기다가 여기에는 Visual Studio 2008으로 이미 컴파일된 바이너리가 따로 OpenCV-2.1.0-win32-vs2008.exe 라는 이름으로 올라와 있습니다. 이제는 CMake 설치하고 직접 소스를 컴파일하느라 시간 낭비할 필요가 없게 되었습니다. Visual Studio 2008과 OpenCV를 연동하는 설치에 대해 간결한 설명은 OpenCV 위키OpenCV 2.1.0 with Visual Studio 2008에 잘 소개되어 있습니다. 여기서는 그 기사에 몇 가지 그림을 곁들어 부연하도록 하겠습니다.

 

OpenCV 2.1 설치

현재 OpenCV 위키의 공식 사이트에 들어가자 마자 보이는 다운로드 링크는 2.0 버전입니다. 그 아래에 있는 OpenCV-2.1.0-win32-vs2008.exe를 다운로드 받도록 합니다.

image_thumb1

 

설치는 다음 버튼만 누르면 됩니다. 단, 중간 Install Options에서 OpenCV 2.1 경로 추가는 하도록 하는 것이 좋겠습니다.

image_thumb7 image_thumb8

image_thumb10

image_thumb11 image_thumb12

image_thumb13 image_thumb14

image_thumb15

 

기본 설정대로 설치를 했다면 OpenCV 2.1은 C:\OpenCV2.1에 설치가 되어 있을 것입니다.

 

Visual Studio 2008 설정

도구-옵션을 선택한 후 프로젝트 및 솔루션-VC++ 디렉터리를 선택합니다. 오른쪽 리스트 박스에서 포함 파일을 선택한 후 “C:\OpenCV2.1\include\opencv”를 추가합니다.

image_thumb19

 

그 다음으로는 라이브러리 파일을 선택해 "C:\OpenCV2.1\lib"를 추가합니다.

image_thumb21

 

소스 파일을 선택한 후 아래의 4개 폴더를 추가합니다.

  • "C:\OpenCV2.1\src\cv"
  • "C:\OpenCV2.1\src\cvaux"
  • "C:\OpenCV2.1\src\cxcore"
  • "C:\OpenCV2.1\src\highgui"

    image_thumb23 

     

    Visual Studio 2008 프로젝트 설정

    Alt-F7을 눌러 프로젝트 속성 대화상자를 호출한 후 구성 속성-링커-입력을 선택합니다.

    image_thumb24

     

    추가 종속성 부분에 "cv210.lib cxcore210.lib highgui210.lib"를 추가합니다.

    image61_thumb

     

    여기까지 하면 Visual Studio 2008에서 OpenCV 2.1을 쓸 수 있도록 설정하는 과정이 완료가 됩니다.

  • + Recent posts