1.제목: C-programming of a Edge Detection2.관련이론1)에지 검출영상 안에서 물체들은 자신만의 경계선을 가지고 있다. 물체의 경계선이 나타내는 에지에서 밝기변화가 있기 때문이다. 인간은 눈으로 이러한 물체들의 에지에서 밝기의 변화를 인지하여 무의식적으로 물체를 구분할 수 있는 것이다.에지란 영상안에 있는 모는 객체의 경계를 가리키는 것으로 모양을 탐지할 수 있는 중요한 정보가 들어있는 요소이다. 따라서 에지란 영상 안에서 물체를 구분할 수 있는 중요한 특징이 될 수 있다.에지 검출이란(edge detection) 에지에 해당하는 픽셀을 영상에서 찾아내는 과정을 뜻한다.따라서 에지의 검출원리인 밝기 값이 급격한 변화가 있는 곳과 완만한 곳을 구분하기 위해서 잡음을 제거하는 전처리 과정이 필수적으로 요구된다. 잡음 제거 영향으로 영상의 밝기값 변화가 둔화되기 때문이다.a루프에지:잡음 제거 후의 라인 에지 부분b라인에지:밝기 값이 갑자기 변하거나 특정 구간을 지나 다시 원래의 값으로 돌아옴c스텝에지:밝기 값이 갑자기 변하는 부분d램프에지:잡음 제거 후의 스텝 에지 부분2)일차 미분방정식과 이차 미분방정식a.일차 방정식가장 간단한 에지 검출 방법의 원리인 일차 방정식은 밝기의 변화를 이용해서 에지를 찾아내는 것이다. 물체의 부분에서 경사가 급격한 밝기 변화가 보일수록 기울기 값은 커지며, 이러한 밝기의 변화 율 즉 기울기를 검출하는 방법이 1차 미분 연산이다.하지만 미분이라고 하더라도 에지 검출에서는 이산화 된 디지털 신호로 처리하므로 식을 그대로 사용할 수 없기에 차등 방정식을 사용해서 한다.왼쪽의 식을 이용한 계산은다음 같이 컨벌루션을 이용해서 필터링을 하기로 한다. 일차 미분을 쓰는 필터는 로벛츠, 소벨, 프리윗 필터가 있으면 소스 코드 설명 때 자세히 살펴보도록 하겠다.b.이차 미분방정식일차미분 영상이 밝기가 천천히 변하는 경우에도 쉽게 반응해서 두꺼운 에지를 가져 영상의 질을 떨어뜨린다. 이와 같은 점을 보완해서 이차 미분방정식을 쓰면 밝기가 서서히 변하는 곳에도 반응하는 것을 둔화시키며 에지의 중십만을 표시하게 고 찾아낸 에지들이 끊기지 않고 연결이 된다.*라플라시안*라플라시안은 대표적인 2차 미분연산자로 방향을 타지 않기 때문에 모든방향의 에지를 강조할 수 있는 특징을 가진다.
1. 과제 설명:십진수의 숫자를 이진수로 바꾸는 프로그램을 작성해 본다. 작성시 수업시간에 배운 스택을 바탕으로 코드를 짠다.2. 기본이론다음과 같이 11을 예로 들면 스택에 차례대로 저장이 된다. 큰 하얀색 블록 두개는 Count와 Top이 있는 Stack 구조체 형태이고 조그만한 블록 중 파란블록은 next, 숫자가 들어간 작은 블록은 data 값이고 작은 블록 두개가 만드는 것이 StackNode 구조체 형태이다*C언어로 선형 리스트로 구현 한 모습이다.3. 소스코드 설명typedef struct tStackNode{element data;struct tStackNode *next;}StackNode; //스택정의//스택을 정의하는 부분이다. 8바이트가 생성됨typedef struct Stack{int count;StackNode *top;}Stack;// 스택헤더정의//스택의 헤더가 정의 되는 부분이다. 위의 그림에서 하얀블록을 나타냄while(dec_value>0){value=dec_value%2; //2를 나눈 나머지를 value 에 저장dec_value=dec_value/2;Push(pStack,value);// value 에 스택을 넣는다.}//스택에 2로 나눈 나머지 모두 저장//2로 나눈 나머지 값을 스택에 차곡차곡 쌓는다. 11을 예로 들면 나누어서 첫 번째로 나오는 나머지는 일의 자리이다. 두 번째로 나눈 값은 2의 자리라서 스택에 쌓아두면 나중에 꺼내서 정렬할때는 가장 큰 자리숫자부터 나와서 정렬하기 편하다.while(pStack->count){bin_value=Pop(pStack); //스택에 저장된 것 다시 꺼냄bin_value+=buffer;if(pStack->count)bin_value*=10;}//이진수 결과값//스택에 저장된 값을 꺼내는 과정이다.4, 실행결과 및 설명5.전체코드#include #include #include typedef int element;typedef struct tStackNode{element data;struct tStackNode *next;}StackNode; //스택정의typedef struct Stack{int count;StackNode *top;}Stack;// 스택헤더정의Stack *CreatStack(void){Stack *pStack;pStack=(Stack*)malloc(sizeof(Stack));if(pStack==NULL)return NULL;pStack->count=0;pStack->top=NULL;return pStack;} //스택의 생성void Push(Stack *pStack,element item){StackNode *pNewNode=(StackNode*)malloc(sizeof(StackNode));if(pNewNode==NULL)returnpNewNode->data=item;pNewNode->next=pStack->top;pStack->top=pNewNode;pStack->count++;} //스택의 삽입element Pop(Stack *pStack){if(pStack->top==NULL)return 0;else{element item=pStack->top->data;StackNode *pOldTop=pStack->top;pStack->top=pOldTop->next;free(pOldTop);pStack->count--;return item;}} //스택의 인출void main (void){int dec_value,bin_value; //10진수로 변환하려는 수element value; //스택에 쌓이는 이진수 값int cnt;Stack *pStack=CreatStack();printf("십진수 입력하시오:");scanf("%d",&dec_value);while(dec_value>0){value=dec_value%2; //2를 나눈 나머지를 value 에 저장dec_value=dec_value/2;Push(pStack,value);// value 에 스택을 넣는다.}//스택에 2로 나눈 나머지 모두 저장while(pStack->count){bin_value=Pop(pStack); //스택에 저장된 것 다시 꺼냄bin_value+=buffer;if(pStack->count)bin_value*=10;}//이진수 결과값}6. 고찰간단하면서도 스택에 대한 이론을 배울 수 있는 좋은 기회였다. 먼저 구조체에 관해서 잘 몰라서 헤멨다 . 2학년 때 고급 프로그래밍 이후로 구조체를 쓸일이 사실상 거의 없었다. 항상 구조체를 정의 할때 struct Stack *pStack 으로 하는 것이 습관이 되어서 그런지 처음 할때도 강의자료를 제대로 안보고 해서 왼쪽과 같이 정의 하였다.컴파일 결과 에러가 났다. 강의 자료를 참고로 다시 오른쪽과 같이 수정 하였더니 잘 되었다.typedef struct {int count;StackNode *top;}Stacktypedef struct Stack{int count;StackNode *top;}Stack 하지만 책을 보았더니 왼쪽 오른 쪽 둘 다 맞는 문법 이라고 한다. 책에서는 이렇게 설명 하였다.typedef struct {int count;StackNode *top;}Stackvoid main(){Stack *pStack // 맞는 정의
HW4: Inorder의 재귀구현과 반복구현1, 과제설명void Inorder(TreeNode *root){if(root==NULL)return;if((root->left==NULL) &&(root->right==NULL)){printf("%c",root->data);}else{printf("(");Inorder(root->left);printf("%c",root->data);Inorder(root->right);printf(")");}}다음 코드는 재귀함수로 나타낸 Infix 코드이다. 이 코드를 반복문을 써서 구현 해보아라.2, 이론1)재귀함수와 반복함수재귀함수는 간단히 얘기하자면 자기 자신을 불러서 연산을 수행하는 함수이다. 자기 자신을 계속 부르는 이윤 나름대로의 장점이 있기 때문이다. 일반적으로 반복문으로 작성을 하면 프로그램의 길이가 길어지고 생각해야 될 부분 또한 많아져 코드 또한 복잡해진다. 그래서 프로그램의 작성이 어려워지는 경우가 있다. 그러한 이유로 재귀함수를 쓴다. 하지만 재귀함수는 문제를 초래할 수 있는 단점이 있다. 재귀함수는 메모리를 엄청나게 소비한다. 즉 원하는 결과를 계속 얻기까지 이전에 불렀던 내용은 스택에 계속 적재해서 오버 플로우를 발생시킨다. 또한 반복문에 비해서 엄청늦다.재귀반복수행시간느림빠름코드복잡도간단복잡오버플로우발생거의 발생안함2)표기법: prefix,infix,postfix왼쪽은 infix와 postfix의 표기법을 나타낸 것이다. prefix는 왼쪽->위쪽->오른쪽 이런 순서로 진행된다.다음 트리를 전위,중위,후위법으로 표시하면 다음과 같다.전위: +*a+bcd중위: (a*(b+c))+d후위: abc+*d+3. 소스코드 분석void Inorder(TreeNode *root){ Stack *pStack=CreateStack();while(1){for(;root;root=root->left){Push(pStack,root);}//스택에 집어넣음root=Pop(pStack);if(root==0) break;printf("%c",root->data);root=root->right;}}Stack *pStack=CreateStack(); 스택 생성for(;root;root=root->left) root가 NULL이 되기 전까지 왼쪽 끝까지 가면서 지나간 root의 주소를 스택에 집어넣음root=Pop(pStack); 가장 왼쪽 가지중 가장 왼쪽에 있는 것의 주소 꺼냄if(root==0) break; 스택이 비었으면 함수 종료printf("%c",root->data);스택이 안비었으면 출력root=root->right; 왼쪽 내용을 출력하였으면 오른쪽 내용 출력4.결과 설명 5.고찰앞서 보았듯이 큰 재귀나 반복이나 출력에는 큰 차이가 없다. 큰 차이는 없어도 해결하지 못한점이 있다. infix로 할 시에 연산 순서를 나타내는 괄호표시가 재귀 방법으로 쓸 때에는 알맞게 출력되게 쓰기 쉬웠는데 iterative의 경우에는 괄호()를 넣을 때 복잡한 조건문을 만들어야 된다는 것을 알게 되었다. 생각이 잘 안 나서 거기 까지는 구현을 못했다. recursive랑 비교했을 iterative는 코드가 복잡하다는 것을 느꼈다. 하지만 이 과제를 통해서 recursive가 조금 느려도 함수를 호출하는 횟수가 많지 않으면 사용하면 편리하다는 생각이 들었다.6, 전체 소스코드BinaryTree.h#include #include#include #include typedef char Element;//typedef struct node *tree_pointer;typedef struct tTreeNode{ Element data;struct tTreeNode *left, *right;}TreeNode;TreeNode * CreateTree(TreeNode *left ,Element item,TreeNode *right);TreeNode * CopyTree(TreeNode *root);void Preorder(TreeNode *root);void Inorder(TreeNode *root);void Postorder(TreeNode *root);typedef TreeNode* element;typedef struct tStackNode{element data;struct tStackNode *next;}StackNode; //스택 노드 정의typedef struct Stack{int count;StackNode *top;}Stack;// 스택 헤더 정의Stack *CreateStack(void){Stack *pStack;pStack=(Stack*)malloc(sizeof(Stack));if(pStack==NULL)return NULL;pStack->count=0;pStack->top=NULL;return pStack;} //스택의 생성void Push(Stack *pStack,element item){StackNode *pNewNode=(StackNode*)malloc(sizeof(StackNode));if(pNewNode==NULL)return;pNewNode->data=item;pNewNode->next=pStack->top;pStack->top=pNewNode;pStack->count++;} //스택의 삽입element Pop(Stack *pStack) //TreeNode의 주소를 받음{if(pStack->top==NULL)return 0;else{//Element item=pStack->top->data;element item=pStack->top->data;StackNode *pOldTop=pStack->top;pStack->top=pOldTop->next;free(pOldTop);pStack->count--;return item;}} //스택의 인출BinaryTree.cpp#include "BinaryTree.h"int main(void) //식:(a*(b+c))+d 을 나타냄{TreeNode *a=CreateTree(NULL,'a',NULL);TreeNode *b=CreateTree(NULL,'b',NULL);TreeNode *c=CreateTree(NULL,'c',NULL);TreeNode *d=CreateTree(NULL,'d',NULL);TreeNode *plus1=CreateTree(b,'+',c);TreeNode *multiply=CreateTree(a,'*',plus1);TreeNode *plus2=CreateTree(multiply,'+',d);int sel;while(1){printf("1.Pre, 2.Inorder 3.Postn");scanf( "%d",&sel);switch(sel){case 1 :Preorder(plus2);break;case 2 : Inorder(plus2);break;case 3 : Postorder(plus2);break;default :break;}char Enter;printf("nEnter 누를 시 화면을 초기화 합니다.n");fflush(stdin);scanf("%c",&Enter);if(Enter=='n')system("cls");}return 0;}void Preorder(TreeNode *root){if(root==NULL)return ;printf("%c",root->data);Preorder(root->left);Preorder(root->right);}///////////////////////////recursive/////////////////////////////////////*void Inorder(TreeNode *root){if(root==NULL)return;if((root->left==NULL) &&(root->right==NULL)){printf("%c",root->data);}else{printf("(");Inorder(root->left);printf("%c",root->data);Inorder(root->right);printf(")");}}*////////////////////////iterative///////////////////////////////////////////void Inorder(TreeNode *root){ Stack *pStack=CreateStack();while(1){for(;root;root=root->left){Push(pStack,root);}root=Pop(pStack);if(root==0) break;printf("%c",root->data);root=root->right;}}void Postorder(TreeNode *root){if(root==NULL)return ;Postorder(root->left);Postorder(root->right);printf("%c",root->data);}TreeNode* CreateTree(TreeNode *left ,Element item,TreeNode *right){TreeNode *pNewNode=(TreeNode*)malloc(sizeof(TreeNode));if(pNewNode==NULL)return NULL;pNewNode->data=item;pNewNode->left=left;pNewNode->right=right;return pNewNode;}TreeNode * CopyTree(TreeNode *root){if(root==NULL)return NULL;
1, 과제설명 어두운 영상을 히스토그램 평활화 시켜 화질 개선을 시켜 본다. 2.이론1)히스토그램이란? 히스토그램의 사전적 의미는 데이터의 특징을 한눈에 알아볼 수 있도록 데이터를 막대그래프모양으로 나타낸 것이다. 예를 들어 한 학급의 키를 히스토 그램으로 나타내면 x축에는 일정한 간격으로 키를 표시해 주고 Y축에는 그 키에 해당하는 인원을 표시하는 것이다. 디지털 영상의 히스토그램도 마찬가지이다. 영상의 화소값을 X축에 나열하고 세로축에는 해당 화소값의 개수를 표현하는 것이다. 2)히스토그램 분포에 따른 명암히스토그램의 명암 대비를 파악하는 방법을 알아보자 기둥이 왼쪽에 치우쳐 있으면 화소의 값이 작아 전체적으로 영상이 진하고 어두워진다. 반면 기둥이 오른쪽으로 치우쳐 있으면 영상이 오른쪽으로 치우쳐 화소 값의 전체적으로 커 영상이 작아진다. 히스토그램 기둥이 좁은 범위에 분포되어 있으면 명암 대비가 좋지 않고 반면에 히스토 그램의 기둥이 넓게 분포되어 있으면 명도차이가 적어 명암 대비가 좋지 않다. 3)히스토그램 평활화카메라로 찍은 영상의 일부분이 너무 어두워서 확인하기 힘들었던 적이 한번 쯤 있었을 것이다. 히스토그램 평활화는 어둡게 촬영된 영상의 히스토그램을 조절하여 명암 분포가 빈약한 영상을 균일하게 만들어 준다. 이 기법은 히스토그램에 덧셈이나 뺄셈 등 산술연산을 수행하지 않아도 분포가 균일하게 되도록 만들어 준다. 평활화는 다음과 같은 단계로 나타낸다.1단계: 명암 j의 빈도수를 계산하여 입력영상의 히스토그램을 생성한다. ....
1.프로젝트 소개 : 수업시간에 배운 single cylce processor을 바탕으로 pipeline processor에 대해 공부한뒤 processor를 설계한다. 파이프라인이란? 컴퓨터에서, 파이프라인이란 프로세서로 가는 명령어들의 움직임, 또는 명령어를 수행하기 위해 프로세서에 의해 취해진 산술적인 단계가 연속적이고, 다소 겹치는 것을 말한다. 파이프라인이 없다면 컴퓨터의 프로세서는 메모리에서 첫 번째 명령어를 가지고 와서, 그것이 요구하는 연산을 수행하고, 그리고 나서 다음번 명령어를 메모리로부터 가져오는 식으로 동작한다. 명령어를 가져오는 동안에, 프로세서의 산술연산부분은 다음 명령어가 도착되기를 기다리며 쉬어야만 한다. 파이프라인을 쓰면, 컴퓨터 구조는 프로세서가 산술연산을 수행하는 동안에 다음번 명령어를 가져올 수 있으며, 그것을 다음 명령어 연산이 수행될 수 있을 때까지 프로세서 근처의 버퍼에 가져다놓는다. 명령어를 가져오는 단계는 끊임없이 계속된다. 그 결과, 주어진 시간동안에 수행될 수 있는 명령어의 수가 증가한다.(구글 백과사전 참고.)그림과 같이 세탁기에 비유할 수 있다. 여러대의 세탁기가 있으면 그중에 쓰고 있는 것도 있고 안 쓰고 있는 것도 있다. single cycle에서는 한 세탁기가 끝날 때 까지 기다렸다가 사용하지만 pipeline은 세탁기를 사용하는 동안 빈 세탁기가 있으면 다른 세탁기를 사용하는 것과 같은 이치이다.교재 406page 7,46을 참고하여 pipeline에서는 5구간(Fetch, Decode, Excute, Memory, Writeback) 으로 나누어서 일을 수행한다.Fetch는 instruction memmory를 수행하고 Decode는 나온 명령어를 regiter에 저장 및 컨트롤 Excute는 alu 연산, Memory는 값을 메모리에 저장하는 구간, Writeback은 처음 자리 Fetch에 돌아가기위한 준비단계이다.