با فیلتر گابور براحتی می تونید آستانه گیری مناسبی برروی تصویر فوق انجام بدید.
cv::Mat getRealGaborKernel(const cv::Size& k_size, float sigma, float theta, float nu, float gamma){
float sigma_x = sigma;
float sigma_y = sigma / gamma;
int nstds = 3;
float k_max = float(CV_PI / 2);
float f = (float)cv::sqrt(2.0);
int x_min, x_max, y_min, y_max;
float c = (float)cos(theta);
float s = (float)sin(theta);
if (k_size.width > 0)
x_max = k_size.width / 2;
else x_max = cvRound(std::max(fabs(nstds * sigma_x * c), fabs(nstds * sigma_y * s)));
if (k_size.height > 0)
y_max = k_size.height / 2;
else y_max = cvRound(std::max(fabs(nstds * sigma_x * s), fabs(nstds * sigma_y * c)));
x_min = -x_max;
y_min = -y_max;
cv::Mat kernel(y_max - y_min + 1, x_max - x_min + 1, CV_32FC1);
float k = k_max / pow(f, nu);
float exy = sigma_x * sigma_y / 2;
float scale_real = k * k / sigma_x / sigma_y;
int x, y;
for (y = y_min; y <= y_max; y++){
float* row = kernel.ptr<float>(y_max - y);
for (x = x_min; x <= x_max; x++){
float xr = x * c + y * s;
float v = scale_real * exp(-(x * x + y * y) * scale_real / 2);
float temp = cos(k * xr) - exp(-exy);
v = temp * v;
row[x_max - x] = v;
}
}
return kernel;
}
cv::Mat getMinMaxImage(cv::InputArray _src_min, cv::InputArray _src_max, float thresh) {
cv::Mat src_min = _src_min.getMat();
cv::Mat src_max = _src_max.getMat();
cv::Mat src_min_abs = cv::abs(src_min);
cv::Mat result = src_max.clone();
result.setTo(-1);
for (size_t i = 0; i < result.rows; i++) {
float* row_min = src_min.ptr<float>(i);
float* row_max = src_max.ptr<float>(i);
float* row_min_abs = src_min_abs.ptr<float>(i);
float* row_result = result.ptr<float>(i);
for (size_t j = 0; j < result.cols; j++)
if (row_min_abs[j] > row_max[j]) {
if (row_min_abs[j] > thresh)
row_result[j] = row_min[j];
}
else {
if (row_max[j] > thresh)
row_result[j] = row_max[j];
}
}
return result;
}
void gaborFilter(cv::InputArray _src, cv::InputOutputArray _dst,int angles_count, int b_size,float thresh){
cv::Mat src = _src.getMat();
cv::Mat src_float;
normalize(src, src_float, 1, 0, CV_MINMAX, CV_32F);
std::vector<int> sizes = { b_size };
cv::Mat min_img, max_img;
for (int k = 0; k < sizes.size(); k++)
for (int i = 0; i < angles_count - 0; i += 2){
for (float j = 0.5f; j <= 2.5f; j += 1.f){
cv::Mat kernel = getRealGaborKernel(Size(sizes[k], sizes[k]), CV_PI * 1, i*CV_PI / angles_count + CV_PI / 2, j, 0.9);
cv::Mat dst;
cv::filter2D(src_float, dst, CV_32F, kernel, cv::Point( -1, -1), 0, BORDER_REPLICATE);
updateMinMaxImages(dst, min_img, max_img);
}
}
const float t = 0.001f;
auto result = getMinMaxImage(min_img, max_img, thresh);
cv::normalize(result, _dst, 0, 255,cv::NORM_MINMAX, CV_8UC1);
}
void gaborFilterBinary(cv::InputArray _src, cv::InputOutputArray _dst, int angles_count, int b_size,float thresh){
gaborFilter(_src, _dst,angles_count,b_size,thresh);
adaptiveThreshold(_dst, _dst, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 35, 4);
}
به صورت زیر هم تستش کنید.
std::string file_name = R"(img.jpg)";
cv::Mat img = cv::imread(file_name, 0);
cv::Mat dst;
gaborFilterBinary(img, dst,30,19);
imshow("dst", dst);
cv::waitKey(0);
خروجی :