반응형
오츠 알고리즘 구현
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int calcOtsh(Mat src) {
int histogram[256] = { 0, };
int otsh_threshold = 0;
double between_variance = 0;
for (int r = 0; r < src.rows; r++)
for (int c = 0; c < src.cols; c++) {
auto color = src.at<Vec3b>(r, c);
int histo = (color[0] + color[1] + color[2]) / 3;
histogram[histo] = histogram[histo] + 1; // 누적 합 구하기
}
// 0 ~ 256 사이의 임계값 구하기
for (int threshold = 0; threshold < 256; threshold++) {
float w0 = 0.0, w1 = 0.0;
float u0 = 0.0, u1 = 0.0;
float u = 0.0;
// w0 계산 (0 ~ t까지의 누적합)
for (int i = 0; i < threshold; i++)
{
w0 += histogram[i];
u0 = (double)(u0 + i * histogram[i] / w0); // w0 평균 구하기
}
// w1 계산 (t + 1 ~ L - 1까지의 누적합)
for (int i = threshold + 1; i < 256; i++)
{
w1 += histogram[i];
u1 = (double)(u1 + i * histogram[i] / w1); // w1 평균 구하기
}
u = (w0 * u0) + (w1 * u1);
double result = w0 * w1 * (u1 - u0) * (u1 - u0);
// 가장 큰 V between(t)를 임계값 T로 취한다.
if (between_variance < result) {
between_variance = result;
otsh_threshold = threshold;
}
}
return otsh_threshold;
}
int main()
{
Mat src = imread("resource01.jpeg", IMREAD_COLOR);
Mat dst, otsu;
int otsh_threshold = calcOtsh(src);
imshow("origin", src);
src = imread("resource01.jpeg", IMREAD_GRAYSCALE);
threshold(src, dst, otsh_threshold, 255, THRESH_BINARY);
imshow("dst", dst);
threshold(src, otsu, 100, 255, THRESH_OTSU);
imshow("otsu", otsu);
waitKey(0);
return 0;
}
threshold에 들어가는 사진 이미지는 grayscale이어야 한다. 대신에 이미지의 색상 알파 값이 없는 형식을 사용하게 되면 에러가 발생함.
사실상 adpative threshold 처럼 여러 개의 임계값을 (지역별로) 사용하는 것이 아니기 때문에, 히스토그램 영역이 두 개로 명확하게 갈리는 사진이 아니라고 하면, 결과값이 좋지 않을 수도 있다.
Flood Fill 구현
#include <opencv2/opencv.hpp>
#include <iostream>
#include <queue>
using namespace cv;
using namespace std;
bool visited[501][501];
Point connectivity[8] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1}, {1, 1}, {-1, 1}, {1, -1}, {-1, -1} };
bool isSameColor(Vec3b a, Vec3b b) {
return a[0] == b[0] && a[1] == b[1] && a[2] == b[2];
}
void bfs_flood_fill(int r, int c, Mat& src, Vec3b flood) {
queue <Point> que;
Vec3b origin = src.at<Vec3b>(Point(c, r));
que.push({ r, c });
src.at<Vec3b>(Point(c, r)) = flood;
while (!que.empty()) {
Point cur = que.front();
que.pop();
for (int i = 0; i < 8; i++) {
int rr = cur.x + connectivity[i].x;
int cc = cur.y + connectivity[i].y;
if (rr < 0 || rr >= src.rows || cc < 0 || cc >= src.cols) continue;
if (visited[rr][cc]) continue;
if (isSameColor(origin, src.at<Vec3b>(Point(cc, rr))))
{
visited[rr][cc] = true;
src.at<Vec3b>(Point(cc, rr)) = flood;
que.push({ rr, cc });
}
}
}
}
int main()
{
Mat src = imread("resource02.png", IMREAD_COLOR);
Mat dst = imread("resource02.png", IMREAD_COLOR);
int count = 0;
for (int r = 0; r < src.rows; r++)
for (int c = 0; c < src.cols; c++) {
if (!visited[r][c]) {
visited[r][c] = true;
Vec3b rand_color = Vec3b((unsigned)theRNG() & 255, (unsigned)theRNG() & 255, (unsigned)theRNG() & 255);
bfs_flood_fill(r, c, dst, rand_color);
}
}
imshow("origin", src);
imshow("result", dst);
waitKey(0);
return 0;
}
임의의 coloring 이미지를 불러와서 색을 칠하도록 했다.
랜덤한 색상을 가져와서 칠해주는 방식인데, 단순 dfs나 bfs 방식으로 구현할 수 있다.
대신 재귀적인 dfs 방식으로 구현하게 되면 스택 오버플로우가 날 가능성이 있다.
반응형
'IT > Graphics' 카테고리의 다른 글
컴퓨터 비전 스터디 6주차 : 21.05.09 (0) | 2021.05.22 |
---|---|
컴퓨터 비전 스터디 5주차 : 21.04.25 (0) | 2021.05.02 |
컴퓨터 비전 스터디 4주차 : 21.04.11 (0) | 2021.04.15 |
컴퓨터 비전 스터디 2주차 : 21.03.28 (0) | 2021.03.27 |
컴퓨터 비전 스터디 1주차 : 21.03.21 (0) | 2021.03.21 |
댓글