Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- D Flip Flop
- gpio
- pwm
- test bench
- verilog
- uart 통신
- DHT11
- Recursion
- ring counter
- FND
- soc 설계
- java
- Edge Detector
- KEYPAD
- BASYS3
- Pspice
- LED
- dataflow modeling
- stop watch
- vivado
- atmega 128a
- behavioral modeling
- prescaling
- Linked List
- structural modeling
- Algorithm
- half adder
- ATMEGA128A
- hc-sr04
- i2c 통신
Archives
- Today
- Total
거북이처럼 천천히
Java - Blob 넓이 구하기 본문
1. 문제
- 0(Background pixel)과 1(Image pixel)로 구성된 Binary 이미지에서 서로 인접한 Image pixel의 집합을 Blob라 한다.
- 상하좌우 + 이웃한 대각선까지 인접한 것으로 간주
- 문제) Binary 이미지에서 Blob의 집합과 그의 크기를 구하기
2. 생각(Recursion Thinking)
본 문제는 하나의 Image pixel를 기준으로 이웃한 Image pixel의 갯수를 반복적으로(?) 세야하기 때문에 재귀 함수(Recursion)를 이용하였다. Recursion Think를 이용하여 단계별로 나누면 다음과 같이 나눌 수 있다.
2.1. 첫 번째 Recursion
- Base Case)
Binary image에서 [0, 0]부터 시작해서 [N-1, N-1]까지 Recursion하는데,
if) row == N-1 && column == N-1 성립하면 Escape한다. - Recursion Case)
if) pixel 값이 1이면 해당 pixel 값을 기준으로 두 번째 Recursion를 실행
else) 다음 pixel로 이동
2.2. 두 번째 Recursion
- Base Case)
if) pixel [row, column] 값이 1이 아니면 Retrun한다. - Recursion Case)
- 지나온 pixel에 Marking하여 지나온 pixel에 되돌아가는 것을 방지한다.
- Blob 면적에 1를 더한다.
- 상하좌우 + 대각선, 총 8개의 방향에 대해서 Recursion한다.
Recursion Thinking을 이용하여 코드를 작성하면 다음과 같이 작성할 수 있다.
private void getBlobInfo(int row, int column, int nameOfBlob)
// ** Base Case
if 현재 셀의 위치가 [N-1, N-1]인지
return;
else
// ** Recursion Case
if 현재 셀의 값이 1인지
// * 현재 셀은 새로운 Blob의 기준점이 된다.
getBlob(row, column, nameOfBlob);
// * 다음 셀로 이동한다.
x++;
if(x==size)
y++; x=0;
// * Recursion
getBlobInfo(row, column, nameOfBlob);
private void getBlob(int y, int x, int name)
// ** 첫 번째 Base case : Binary image 영역 밖인지
if(x<0 || x>=size || y<0 || y>=size)
return;
// ** 두 번째 Base case : 해당 셀의 값이 1인지
else if(pixels[y][x] != 1)
return;
// ** Recursion Case
else
// * 현재의 셀을 1이 아닌 값으로 Marking하여 다시 가는 것을 방지
pixels[y][x] = name
// * 현재 카운트하고 있는 blob의 면적에 1을 더하기
// * 상하좌우 + 대각선에 대해서 Recursion
getBlob(y+1, x, newBlob, name);
getBlob(y, x+1, newBlob, name);
getBlob(y-1, x, newBlob, name);
getBlob(y, x-1, newBlob, name);
getBlob(y+1, x-1, newBlob, name);
getBlob(y+1, x+1, newBlob, name);
getBlob(y-1, x+1, newBlob, name);
getBlob(y-1, x-1, newBlob, name);
3. 풀이 및 코드 분석
public class Test {
private static int[][] pixels = {{1, 0, 0, 0, 0, 0, 0, 1},
{0, 1, 1, 0, 0, 1, 0, 0},
{1, 1, 0, 0, 1, 0, 1, 0},
{0, 0, 0, 0, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 1, 0, 0},
{1, 0, 0, 0, 1, 0, 0, 1},
{0, 1, 1, 0, 0, 1, 1, 1}};
private static int size = pixels.length;
private static ArrayList<Blob> blobs = new ArrayList<>();
// ** Main method
public static void main(String[] args) {
getBlobInfo(0, 0, 2);
// * Binary image에서 같은 Blob끼리 묶어서 표시하고, 출력
printPixels();
// * 확인된 Blob에 대해서 면적 출력
printBlobsInfo();
}
// ** Inner class
private static class Blob{
private int nameOfBlob;
private int size;
public Blob(int name) {
nameOfBlob = name;
size = 0;
}
public int getName() {
return nameOfBlob;
}
public int getSize() {
return size;
}
public void setName(int newName) {
nameOfBlob = newName;
}
public void setSize(int newSize) {
size = newSize;
}
}
private static void getBlobInfo(int y, int x, int name) {
if(y==size-1 && x==size-1)
return;
else {
if(pixels[y][x]==1) {
Blob newBlob = new Blob(name);
getBlob(y, x, newBlob, name);
blobs.add(newBlob);
name++;
}
x++;
if(x==size) {
y++;
x=0;
}
getBlobInfo(y, x, name);
}
}
private static void getBlob(int y, int x, Blob newBlob, int name) {
if(x<0||x>=size||y<0||y>=size)
return;
else if(pixels[y][x]!=1)
return;
else {
pixels[y][x] = name;
int blobArea = newBlob.getSize();
newBlob.setSize(++blobArea);
getBlob(y+1, x, newBlob, name);
getBlob(y, x+1, newBlob, name);
getBlob(y-1, x, newBlob, name);
getBlob(y, x-1, newBlob, name);
getBlob(y+1, x-1, newBlob, name);
getBlob(y+1, x+1, newBlob, name);
getBlob(y-1, x+1, newBlob, name);
getBlob(y-1, x-1, newBlob, name);
}
}
private static void printPixels() {
System.out.println("Pixel image: ");
for(int row=0; row<size; row++) {
for(int column=0; column<size; column++) {
if(pixels[row][column]!=0)
System.out.printf(" %d", pixels[row][column]-1);
else
System.out.printf(" %d", pixels[row][column]);
}
System.out.println();
}
}
private static void printBlobsInfo() {
if(blobs.size()==0)
System.out.println("There is no blob.");
else {
System.out.println("\nBlob information: ");
for(int i=0; i<blobs.size(); i++)
System.out.printf("Blob[%d]'s size = %d\n", blobs.get(i).getName()-1, blobs.get(i).getSize());
}
}
}
Pixel image:
1 0 0 0 0 0 0 2
0 1 1 0 0 3 0 0
1 1 0 0 3 0 3 0
0 0 0 0 0 3 0 0
0 4 0 3 0 3 0 0
0 4 0 3 0 3 0 0
4 0 0 0 3 0 0 3
0 4 4 0 0 3 3 3
Blob information:
Blob[1]'s size = 5
Blob[2]'s size = 1
Blob[3]'s size = 13
Blob[4]'s size = 5
4. 메모
- 코드를 작성하기 전에 대략적인 알고리즘에 대해서 생각하자.
- 처음에 알고리즘을 생각하지 않고, 무작정 코드를 작성했지만, 중간에 예상치 못한 문제와 오류가 발생하여 혼란스
러웠다. 하지만, 전체적인 알고리즘을 생각하고, 정리한 뒤, 다시 한 번 작성하자 쉽게 해결할 수 있었다. - Recursion의 Base structure를 꼭 생각하고, 이용하자.
1) Recursion은 Base case와 Recursion Case로 나눈다.
2) Recursion case는 반드시 Base case로 수렴해야한다.
3) Implicit parameter보다 Explicit parameter를 사용하자. (대신 생략할 수 있으면 생략하자.)
- 어떠한 Recursion 문제도 위 규칙들을 크게 벗어나지 않는다. 그러니 위 규칙을 반드시 명심하자.
'Algorithm > 알고리즘 문제 풀이' 카테고리의 다른 글
Java - 1, 2, 3 더하기 (0) | 2022.10.12 |
---|---|
Java - n Queen Problem (0) | 2022.10.09 |
Java - 미로 찾기 (2) | 2022.10.04 |
Java - 싱글 연결리스트를 통해 다항식 계산 (0) | 2022.08.11 |
알고리즘 (6월 30일) (0) | 2022.06.30 |