1. Derivative Based Algorithms:

  • Thresholded absolute gradient: $$ f  =\sum_x \sum _y |I (x+1, y) - I(x, y)| $$  where   $|I(x+1, y) - I(x, y)| > \text{threshold};$
  • Squared gradient: $$f=\sum_x \sum_y ( I(x+1, y)- I(x, y)) ^2 $$ where $(I(x+1, y) - I(x, y))^2 > \text{threshold};$
  • Brenner gradient: $$f=\sum_x \sum_y ( I(x+2, y)- I(x, y)) ^2 $$ where $(I(x+2, y) - I(x, y))^2 > \text{threshold};$
  • Tenenbaum gradient: $$f = \sum_x \sum_y (\text{SobelX}^2 (x, y)+ \text{SobelY}^2(x,y));$$
  • Energy Laplace: $$f = \sum_x \sum_y ( (L * I) (x, y))^2$$  where $$L =\left[\begin{array}{ccc} -1& -4 & -1 \\  -4 & 20 & -4 \\ -1 & -4 & -1 \end{array}  \right]$$ 
  • Sum of modified Laplace: $$f = \sum_x \sum_y (\text{LaplaceX}(x, y)| + |\text{LaplaceY}(x, y)|) $$
  • Sum of squared Gaussian derivatives $$f = \frac{1}{\text{total pixels}} \sum_x \sum_y ((\text{Gaussian derivative X}(x,y)) ^2 + (\text{Gaussian derivative Y}(x,y))^2 )$$ where $\sigma  = d/(2\sqrt{3})$, $d$ = dimension of the smallest feature;

 

2. Statistical Algorithms:

  •  Variance Measure ; $$f = \frac{1}{\text{total pixels}}\sum _x \sum _y ( I  (x, y) - \overline{I})^2;$$ where $\overline{I}$ is the mean of image.
  • Normalized Variance Measure ; $$f = \frac{1}{\text{total pixels}\times \overline{I}} \sum_x \sum_y ( I(x, y)- \overline{I})^2;$$
  • Auto-correlation Measure: $$f = \sum_x\sum_y I(x, y) I(x+1, y) - \sum _x \sum_y I(x, y) I(x+2, y);$$
  • Standard Deviation-based Correlation: $$f = \sum_x \sum_y I(x, y) I(x+1, y) - \overline{I}^2(x, y)\times \text{total pixels};$$

3. Histogram-based Algorithms:

  • Range Algorithm: $$f =\text{max}\{i| \text{histogram}(i)>0\} - \text{min}\{ i| \text{histogram}(i)>0\};$$
  • Entropy Algorithm: $$f=-\sum_{i=0}^{255} p(i) \log_{2} p(i)$$ where $p(i)= \text{histogram}(i)/\text{total pixels};$

4. Other Algorithms:

  • Threshold Contents: $$f=\sum_x \sum_y I(x, y)$$ where $I(x,y) \ge \text{threshold};$
  • Thresholded Pixel Count: $$f=\sum_x\sum_y \theta(\text{threshold}- I(x, y));$$ where $\theta(x)$ is the step-function.
  • Image Power: $$f= \sum_{x}\sum_{y} I^2(x, y)$$ where $I(x, y) \ge\text{threshold};$

Ref: Dynamic evaluation of autofocusing for automated microscopic analysis of blood smear and pap smear, J. Microscopy,227, 15(2007).                           

 

728x90

'Image Recognition' 카테고리의 다른 글

Union-Find Connected Component Labeling  (0) 2012.11.01
RANSAC: Ellipse Fitting  (1) 2012.10.07
Statistical Region Merging  (2) 2012.03.25
Local Histogram Equalization  (0) 2012.03.10
2차원 Savitzky-Golay Filters 응용  (0) 2012.02.28
Posted by helloktk
,

영상에서 추출한 객체(object)의 경계선은 객체의 모양에 대한 많은 정보를 담고 있지만, 어떤 경우에는 불필요하게 많은 정보가 될 수도 있다. 이 경우 원래의 경계를 충분히 닮은 다각형으로 간략화하여서 불필요한 정보를 제거할 수 있다. 이 다각형으로의  근사가  물체의 경계를 얼마나 제대로 표현할 수 있는지에 대한 기준이 있어야 한다. $N$개의 점 $\{(x_i, y_i) | i = 1,... ,N\}$으로 표현된 경계가 있다고 하자. 가장 단순한 근사는 가장 멀리 떨어진 두 점($A, B$)으로 만들어진 선분일 것이다(선분의 길이가 대략적인 물체의 크기를 주고, 선분 방향이 물체의 orientation을 알려준다). 이 선분을 기준으로 다시 가장 멀리 떨어진 점($C$)을 찾아서 일정 거리 이상 떨어져 있으면 꼭짓점으로 추가하여 두 개의 선분으로 분할한다. 두 개의 선분에 대해서 동일한 분할 작업을 재귀적으로 반복하므로 좀 더 정밀하게 물체를 표현하는 다각형을 찾을 수 있다. 선분에서 가장 멀리 떨어진 지점이 기준 거리 이내이면 분할을 멈춘다. 닫힌 다각형 근사일 때는 시작점 = 끝점으로 조건을 부여하면 된다.

** open polyline으로 우리나라 경계를 단순화시키는 예: top-right 쪽이 시작과 끝이므로 simplication 과정에서 변화지 않는다.

// distance square from P to the line segment AB ;

double pt2SegDist2(CPoint P, CPoint A, CPoint B) ;

더보기
// P에서 두 점 A, B을 연결하는 선분까지 거리
double pt2SegDist2(CPoint P, CPoint A, CPoint B) {
    double dx = B.x - A.x, dy = B.y - A.y ;
    double lenAB2 = dx * dx + dy * dy ;
    double du = P.x - A.x, dv = P.y - A.y ;
    if (lenAB2 == 0.) return du * du + dv * dv;
    double dot = dx * du + dy * dv ; 
    if (dot <= 0.) return du * du + dv * dv;
    else if (dot >= lenAB2) {
        du = P.x - B.x; dv = P.y - B.y;
        return du * du + dv * dv;
    } else {
        double slash = du * dy - dv * dx ;
        return slash * slash / lenAB2;
    }
};

//  recursive Douglas-Peucker 알고리즘;

void DouglasPeucker(double tol, std::vector<CPoint>& vtx, int start, int end, 
                   std::vector<bool>& mark) {
    if (end <= start + 1) return; //종료 조건;
    // vtx[start] to vtx[end]을 잇는 선분을 기준으로 분할점을 찾음;
    int break_id = start;			// 선분에서 가장 먼 꼭짓점;
    double maxdist2 = 0;
    const double tolsq = tol * tol;		
    for (int i = start + 1; i < end; i++) {
        double dist2 = pt2SegDist2(vtx[i], vtx[start], vtx[end]);
        if (dist2 <=  maxdist2) continue;
        break_id = i;
        maxdist2 = dist2;
    } 
    if (maxdist2 > tolsq) {		// 가장 먼 꼭짓점까지 거리가 임계값을 넘으면 => 분할;
        mark[break] = true;		// vtx[break_id]를 유지;
        // vtx[break_id] 기준으로 좌/우 polyline을 분할시도;
        DouglasPeucker(tol, vtx, start, break_id, mark);
        DouglasPeucker(tol, vtx, break_id, end, mark);
    }
};

// driver routine;

int polySimplify(double tol, std::vector <CPoint>& V, std::vector <CPoint>& decimated) {
    if (V.size() < 2) return 0;    
    std::vector<bool> mark(V.size(), false); // 꼭짓점 마킹용 버퍼;
    // 알고리즘 호출 전에 너무 붙어있는 꼭짓점을 제거하면 보다 빠르게 동작;
    // 폐곡선이 아닌 경우 처음,끝은 marking; 
    // 폐곡선은 가장 멀리 떨어진 두점중 하나만 해도 충분;
    mark.front() = mark.back() = true; 
    DouglasPeucker( tol, V, 0, V.size()-1, mark );
    // save marked vertices;
    decimated.clear();    
    for (int i = 0; i < V.size(); i++)
        if (mark[i]) decimated.push_back(V[i]);
    return decimated.size();
}

nonrecursive version:

// nonrecursive version;
int DouglasPeucker_nonrec(double tol, std::vector<CPoint>& points,
                            std::vector<CPoint>& decimated) {
    if (points.size() <= 2) return;
    double tol2 = tol * tol; //squaring tolerance;
    // 미리 가까이 충분히 가까이 있는 꼭지점은 제거하면 더 빨라짐;
    std::vector<CPoint> vt;
    vt.push_back(points.front()) ;  // start at the beginning;
    for (int i = 1, pv = 0; i < points.size(); i++) {
        int dx = points[i].x - points[pv].x, dy = points[i].y - points[pv].y;
        double dist2 = dx * dx + dy * dy ;
        if (dist2 < tol2) continue;
        vt.push_back(points[i]); 
        pv = i; // 다시 거리를 재는 기준점;
    }
    if (vt.back()!=points.back()) vt.push_back(points.back());  // finish at the end
    points.swap(vt);
    //
    std::vector<bool> mark(points.size(), false); // vertices marking
    std::vector<int> stack(points.size());  // 분할된 라인 처음-끝 저장;
    // 폐곡선이 아닌 경우 처음,끝은 marking; 
    // 폐곡선은 가장 멀리 떨어진 두점 중 하나만 해도 충분
    mark.front() = mark.back() = true;
    int top = -1;
    // 분할 해야할 폴리라인의 양끝점을 스택에 넣음;
    stack[++top] = 0;
    stack[++top] = points.size() - 1;
    while (top >= 0) {
        // 분할을 시도할 구간의 두 끝점을 꺼냄;
        int end = stack[top--];
        int start = stack[top--];
        // 최대로 멀리 떨어진 점;
        double max_distance2 = 0;
        int break_id = -1;
        for (int i = start + 1; i < end; i++) {
            double dsq = pt2SegDist2(points[i], points[start], points[end]);
            if (dsq > max_distance2) {
                max_distance2 = dsq;
                break_id = i;
            }
        }
        // 주어진 임계값 이상 떨어졌으면 꼭지점을 유지하도록 표시;
        if (max_distance2 > tol2) {
            mark[break_id] = true;       
            // 주어진 꼭지점을 기준으로 양쪽을 다시 검사하기 위해 스택에 쌓음;
            stack[++top] = start;
            stack[++top] = break_id;
            stack[++top] = break_id;
            stack[++top] = end;
        }
    }
    // marking 된 꼭지점을 출력;
    decimated.clear();
    for (int i = 0; i < points.size(); i++)
        if (mark[i]) decimated.push_back(points[i]);
    return decimated.size();
}
728x90
Posted by helloktk
,

http://www.lix.polytechnique.fr/~nielsen/tpami04-nn.pdf

Abstract—This paper explores a statistical basis for a process often described in computer vision: image segmentation by region merging following a particular order in the choice of regions. We exhibit a particular blend of algorithmics and statistics whose segmentation error is, as we show, limited from both the qualitative and quantitative standpoints. This approach can be efficiently approximated in linear time/space, leading to a fast segmentation algorithm tailored to processing images described using most common numerical pixel attribute spaces. The conceptual simplicity of the approach makes it simple to modify and cope with hard noise corruption, handle occlusion, authorize the control of the segmentation scale, and process unconventional data such as spherical images. Experiments on gray-level and color images, obtained with a short readily available C-code, display the quality of the segmentations obtained. 

인간은 영상을 보면 매우 쉽게 비슷한 픽셀 값을 갖는 영역으로 분리해서 인식을 한다. 우리가 보는 영상이 여러 개의 균일한 영역으로 나누어진 기본 영상에 랜덤 노이즈가 추가되어 만들어졌다고 생각해보자. 영상의 픽셀 값이 기본 영상의 픽셀 값에 일정 구간(Q)에서 값을 취하는 랜덤 변수가 더해져서 만들어졌다고 보면, 영상에서 다른 두 영역($R, R'$)의 픽셀 평균값의 차이 $(\overline{R}-\overline{R'})$와 기본 영상에서 랜덤 변수에 의한 통계적 기댓값의 차이 $(E(\overline{R}-\overline{R'}))$는 주어진 $0 < δ < 1$ 에 다음식을 만족함을 보일 수 있다.

따라서, 두 영역 $R$과 $R'$에 대해서 우변의 값이 이 부등식을 만족하지 않으면 두 영역은 하나로 인식될 수 있다.

 

#region count = 576; 많은 영역이 1픽셀로 구성이 되었있다;
#region count > 1 = 302;
#region count > 2 = 222;
#region count > 3 = 179;
#region count > 4 = 140;

 

 

728x90

'Image Recognition' 카테고리의 다른 글

RANSAC: Ellipse Fitting  (1) 2012.10.07
Autofocus Algorithm  (0) 2012.06.03
Local Histogram Equalization  (0) 2012.03.10
2차원 Savitzky-Golay Filters 응용  (0) 2012.02.28
webcam용 QR code detector  (0) 2012.02.19
Posted by helloktk
,

Histogram equalization(HE)은 histogram을 이용해서 이미지의 contrast을 조정하는 영상처리 기법이다. 히스토그램을 얻기 위해서 전체 이미지 픽셀을 사용하는 전역 HE와 각 픽셀을 중심으로 하는 국소 윈도의 픽셀만 가지고 만든 히스토그램을 이용한 국소 HE이 있다.

 

여기서는 각 픽셀에 대해서 정사각형의 국소 윈도(wsize x wsize)를 잡고, 이 윈도 영역의 국소 히스토그램 정보를 이용해서 HE를 수행한다. 각 윈도 안 픽셀의 히스토그램이 $\{h[i]\}$로 주어질 때, 윈도 중심에서의 픽셀 값 $j$는 

$$j \quad \longrightarrow \quad \frac{255}{\text{total pixels}}\sum_{k=0}^{j} h[k],$$

로 변환된다. 국소 히스토그램 $h[i]$은 running algorithm을 이용하면 빠르게 계산할 수 있다. 단, 국소 윈도가 이미지 영역 내에 있도록 선택했기 때문에 경계 부근의 픽셀은 윈도 중심이 아니다.

//

void localHistogramEqualization(BYTE *image, int width, int height, 
                                             int wsize, /*window size*/
                                             BYTE *out) {
    int hwsize = wsize >> 1;
    wsize = (hwsize << 1) + 1; //odd #;
    int topstop = height - wsize;
    int leftstop = width - wsize; 
    for (int y = 0, offset = 0; y < height; y++, offset += width) {
        int top = y - hwsize; 
        top = top < 0 ? 0 : top > topstop ? topstop : top; 
        BYTE *imgrow = &image[offset];
        BYTE *outrow = &out[offset];
        for (int x = 0; x < width; x++) {
            int left = x - hwsize;
            left = left < 0 ? 0 : left > leftstop ? leftstop : left;
            //make local histogram;
            int histo[256] = ; 
            for (int yy = 0, woffset = top * width + left; yy < wsize; yy++, woffset += width) {
                BYTE * winrow = &image[woffset];
                for (int xx = 0; xx < wsize; xx++) {
                    histo[winrow[xx]]++;
                }
            }
            int level = imgrow[x];
            int csum = 0;  // 0-th cumulative sum up to level;
            for (int k = 0; k <= level; k++) csum += histo[k];
            // apply local histogram eq.
            int a = int((255.0 * csum)/(wsize * wsize)) ;
            outrow[x] = (a & ~255) == 0 ? a: a < 0 ? 0: 255;
        }
    }
}

원본:

 

 

 

*global: 

 

 

 

 

*local: wsize=51;

 

 

** CLAHE 적용: tile size = 20x 20

 

 

 

728x90

'Image Recognition' 카테고리의 다른 글

Autofocus Algorithm  (0) 2012.06.03
Statistical Region Merging  (2) 2012.03.25
2차원 Savitzky-Golay Filters 응용  (0) 2012.02.28
webcam용 QR code detector  (0) 2012.02.19
Least Squares Estimation of Perspective Transformation  (4) 2012.02.15
Posted by helloktk
,

Savitzky-Golay 필터는 일차원의 데이터에 대해 이동평균을 취하는 경우와 같은 방식으로 동작하는 필터이지만, 윈도의 모든 점에 동일한 가중치를 주는 이동평균과 다르게 윈도 픽셀 값을 보간하는 다항식을 최소자승법으로 찾아서 해당 지점의 값으로 할당하는 방식을 택한다(frequency domain에서 분석하면 Savitzky-Golay 필터의 특성, 예를 들면, 피크의 위치가 잘 유지되는 점과 같은 특성을 좀 더 다양하게 볼 수 있다). 이 필터를 쓰기 위해서는 다항식의 찾수와 윈도 크기를 정해야 한다. (다항식의 찾수가 정해지면 최소 윈도 크기는 정해진다).

동일한 방식으로 이차원에 대해서도 Savitzky-Golay를 적용할 수 있다. 이 경우 다항식은 $(x, y)$의 2 변수 함수로 2차원 평면에서 정의되는 곡면으로 나타낸다. 2차원 영상의 경우도 국소 필터를 사용할 수 있지만, 필터 윈도를 영상 전체로 잡아서 전 영역을 보간하는 곡면을 찾을 수도 있다. 배경 조명이 균일하지 않는 영상의 경우 이 곡면을 이용하면 조명에 의한 효과를 예측할 수 있고, 이를 보정한 영상을 이용하면 인식에 도움을 받을 수 있다. (문자 인식에서 문서를 스캔할 때 생기는 균일하지 않은 배경이나, 2차원 바코드 인식에서 배경의 추정 등 다양한 부분에서 사용할 수 있다. 좀 더 간단하게는 배경의 변화를 균일하게 기울어진 평면으로 근사를 하여 추정할 수 있다) 

3차 다항식으로 영상을 보간하는 경우: \begin{align} I(x, y)&= a_{00}\\ &+a_{10} x + a_{01} y \\ &+a_{20} x^2 + a_{11} xy + a_{02} y^2\\ &+a_{30} x^3+a_{21} x^2y+a_{12} xy^2+a_{03} y^3, \quad (x, y)\in \mbox {image} \end{align}

다항식은 $x= [a_{00}, a_{10},..., a_{03}]^T$ 의 10개의 필터 계수를 추정하면 얻어진다. 추가적으로 Savitzky-Golay을 이용하면 영상의 미분 값을 쉽게 구할 수 있다. 로컬 버전의 필터인 경우에 필터 적용 값은 윈도의 중심인 $(x, y) = (0, 0)$에서 다항식 값인 $a_{0}$이다. 이 지점에서 $x$-방향의 편미분 값은 $a_{10}$, $y$-방향의 편미분 값은 $a_{01}$로 주어진다.

필터의 계수 $x$는 최소자승법을 적용하면 얻을 수 있다. 위의 다항식에 $N(= width\times height)$개의 픽셀로 구성된 영상의 각 픽셀에서 좌표와 픽셀 값을 대입하면, $N$개의 식을 얻는다. 이를 행렬로 표현하면, 

$$\bf A\cdot x = b$$

$\bf A$는 $N\times10$ 의 행렬로 각 행은 픽셀의 좌표로 구해진다: 

$${\bf A} =\left[ \begin{array}{cccccccccc} 1&x_0&y_0&x_0^2&x_0y_0&y_0^2&x_0^3&x_0^2y_0&x_0y_0^2&y_0^3\\ 1&x_1&y_1&x_1^2& x_1y_1& y_1^2& x_1^3& x_1^2 y_1 & x_1 y_1^2 & y_1^3\\ 1& x_2& y_2 &x_2^2 & x_2 y_2& y_2^2 & x_2^3 & x_2^2 y_2 & x_2 y_2^2 & y_2^3 \\ &&&&\vdots \end{array} \right]$$

여기서, $i$-번째의 픽셀 위치가 $(x_i, y_i)$로 주어진 경우다. $\bf b$는 $N$-(열) 벡터로 각 픽셀 위치에서 픽셀 값을 나타내는 벡터다: 

$${\bf b}=\left[\begin{array}{c} I(x_0, y_0)\\I(x_1,y_1)\\I(x_2, y_2)\\ \vdots \end{array}\right]$$

최소자승법을 적용하면, 추정된 다항식의 계수 벡터 $\bf x$는 $|\bf A\cdot x - b|^2$을 최소로 하는 벡터로,

$$\bf x = (A^T \cdot A)^{-1} \cdot A^T \cdot b$$

로 주어짐을 알 수 있다. $\bf A^T \cdot A$는 $10\times 10$의 대칭 행렬로 역행렬은 쉽게 구할 수 있다.

이렇게 추정된 2차원 곡면은 영상에서 추정된 배경의 픽셀 값 분포를 의미한다. 문자인식의 예를 들면, 보통 경우에 흰 배경에 검은색 활자를 인식한다. 스캔된 영상에 검은색 활자 때문에 추정된 곡명은 일반적으로 주어진 픽셀이 만드는 곡면보다도 낮게 된다. 픽셀 값이 추정된 곡면보다 더 낮은 픽셀들은 보통 검은색 문자들을 의미하므로, 이 차이의 평균값을 구하면, 대략적으로 어떤 픽셀이 배경에 속하는지 (곡면과 차이가 평균보다 작고, 또한 픽셀 값이  곡면의 아래에 놓인 경우), 아니면 문자 영역인지(곡면과 차이가 평균보다 크고, 픽셀 값이 곡면의 아래에 놓인 경우)를 구별할 있게 된다.   

이제 이 정보들을 이용해서 추정을 다시 하는데 이번에는 1차 추정에서 글씨 영역으로 분류된 픽셀을 제외하고 배경을 추정하면 좀 더 정확한 배경을 기술하는 곡면을 얻을 수 있다.
로컬 필터로 사용할 때는 1차원에서와 마찬가지로 필터 계수를 lookup table로 만들어서 사용할 수 있으나, 전 영역을 대상으로 할 때는 행렬의 크기가 매우 커져서 연산량도 많아진다. 

영상:

 

1차 추정 배경 영상:

 

2차 추정 배경 영상:

 

728x90

'Image Recognition' 카테고리의 다른 글

Statistical Region Merging  (2) 2012.03.25
Local Histogram Equalization  (0) 2012.03.10
webcam용 QR code detector  (0) 2012.02.19
Least Squares Estimation of Perspective Transformation  (4) 2012.02.15
Perspective Transformation  (2) 2012.02.14
Posted by helloktk
,