이미지에서 동일한 색깔의 픽셀을 순회하는 방법?

lacovnk의 이미지

이미지에서, 동일한 색깔의 픽셀을 순회하는 방법을 찾고 있습니다.
(대각선은 가지 않는다고 가정하지요~)

visit(pixel(x,y)) - (x,y)의 pixel과 같은 색깔을 순회하는 함수

visit(pixel(x,y))
{
 if(아래것과 색깔 같으면) visit(pixek(x,y+1);
 // 왼쪽, 위, 오른쪽에도 동일하게
}

그러나 이렇게 하면 갔던 녀석을 또 갈테니..

visit(pixel(x,y)) - (x,y)의 pixel과 같은 색깔을 순회하는 함수

visit(pixel(x,y))
{
  if(!flag)
  {
    set flag on pixel(x,y)
    if(아래것과 색깔 같으면) visit(pixek(x,y+1);
    // 왼쪽, 위, 오른쪽에도 동일하게
  }
  else return;
}

이렇게 하면 해결이 되겠지요? 음음. (과..과연)

그런데, recursive하지 않게 이 문제를 해결할 수 있는 방법은 없을까요? 궁금합니다. 어떻게 보면 굉장히 얽힌 graph문제 같은데..

tinywolf의 이미지

예전에 재귀적으로 구현된 정점 페인트 알고리즘이라 비슷하군요..
그때 자바의 함수 스택 깊이가 한참 모자라서 이터레이티브하게 바꿨었는데..
지금은 기억이 안나므로 패스!

ㅡ_ㅡ;

아르아의 이미지

이런방법은 어떨까요. 스텍에 방문할곳을 쌓아두면서 방문하는 방법입니다

set startpoint = (x,y);
if(아래것과 색깔 같으면)
    push_point((x,y+1));
// 왼쪽, 위, 오른쪽에도 동일하게

while(stack_length!=0){
    pop_point();
    set flag on current point;
    if(아래것과 색깔 같으면)
        if((x,y+1) is not set flag) //(그 아래것이)방분해본적이 없는 점이면
            push_point((x,y+1));
    // 왼쪽, 위, 오른쪽에도 동일하게
}

스택대신 링크드리스트를 쓰는 방법도 있겠네요.
이경우 스택의 최대길이를 어떻게 잡느냐
(메모리 문제가 안된다면 그냥 그림크기만큼 잡아버림 되겟죠)
하는 문제는 생각 안해도 되니까요
lacovnk의 이미지

int
count_partition_color(const Image& image,bool checkBlack)
{
        const int MAX_PARTITION = count_nonWhitePixel(image);
        int label_ref[MAX_PARTITION];
        for(int i=0;i<MAX_PARTITION;i++){label_ref[i] = 0;}

        // init label
        int label[image.getWidth()][image.getHeight()];
        for(unsigned int y=0;y<image.getHeight();y++){for(unsigned int x=0;x<image.getWidth();x++){label[x][y] = -1;}}
                                                                                                                                                                        int number_of_label = 0;
        for(unsigned int y=0;y<image.getHeight();y++)
        {
                for(unsigned int x=0;x<image.getWidth();x++)
                {
                        if(true == checkBlack)
                        {
                                if(true == pixelIsWhite(image.getPixel(x,y))){continue;}
                        }
                        else
                        {                                                                                                                                                                       if(false == pixelIsWhite(image.getPixel(x,y))){continue;}                                                                                               }
                        int label_up = -1;
                        int label_left = -1;;
                        if(y > 0){label_up = label[x][y-1];}
                        if(x > 0){label_left = label[x-1][y];}

                        // both is not labeled
                        if(-1 == label_up && -1 == label_left)
                        {
                                label[x][y] = number_of_label;
                                label_ref[number_of_label] = number_of_label;
                                number_of_label++;
                        }
                        // only one is labeled
                        else if((-1 == label_up && -1 != label_left) || (-1 != label_up && -1 == label_left))
                        {
                                label[x][y] = (label_up == -1)?(label_ref[label_left]):(label_ref[label_up]);
                        }
                        // both is labeled
                        else
                        {
                                // same label
                                if(label_ref[label_up] == label_ref[label_left])
                                {
                                        label[x][y] = label_ref[label_up];
                                }
                                // different label
                                else
                                {
                                        int target = MIN(label_ref[label_up],label_ref[label_left]);
                                        // update other label_ref
                                        for(int k=0;k<number_of_label;k++)

 {
                                                if(label_ref[k] == label_ref[label_up] || label_ref[k] == label_ref[label_left] || label_ref[k] == label_up || label_ref[k] == label_left){label_ref[k] = target;}
                                        }
                                        label[x][y] = label_ref[label_up] = label_ref[label_left] = target;
                                }
                        }
                }
        }
        // if you want to see label... uncomment below part
        /*
        for(unsigned int y=0;y<image.getHeight();y++)
        {
                for(unsigned int x=0;x<image.getWidth();x++)
                {
                        label[x][y] = label_ref[label[x][y]];
                        printf("%2d",label[x][y]);
                }
                cout << endl;
        }
        */
        int result = 0;
        for(int i=0;i<number_of_label;i++){if(label_ref[i] == i){result++;}}
        return result;
}

label을 불여서 partitioning을 했습니다. 이후, 색칠할 픽셀과 같은 파티션인 녀석만 칠해주면 되겠지요~

대략 언뜻 O(n^2)는 넘는 것 같은데.. 다른 label일 경우 일치하게 해 주는 부분이 얼마나 걸릴지 모르겠네요. (으으)

lifthrasiir의 이미지

위키백과를 참고하세요. 보통 일반적인 Flood fill을 하면서 가로로 최대한 확장하는 방법을 쓰는 것 같습니다. (세로로 확장할 수도 있는데 일반적으로 이미지는 가로로 배열하니까...)

- 토끼군

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.