33 if (input.channels() == 3) {
34 LOG_WARN <<
"Converting to grayscale";
35 cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
41 if (gray.type() != CV_8UC1) {
43 gray.convertTo(gray, CV_8UC1);
46 cv::Mat output = gray.clone();
48 if (method ==
"high") {
49 cv::threshold(output, output, level, level, cv::THRESH_TRUNC);
50 }
else if (method ==
"low") {
51 output.setTo(level, output < level);
61 const std::vector<int>& param_filt,
62 const std::pair<double, double>* gs_boundaries) {
64 std::vector<cv::Mat> filtered_images;
65 std::pair<double, double> boundaries;
68 for (
const auto& img : input) {
70 filtered_images.push_back(filtered);
74 if (gs_boundaries ==
nullptr) {
76 LOG_DEBUG <<
" Computed filter boundaries: [" << boundaries.first <<
", " << boundaries.second <<
"]";
78 boundaries = *gs_boundaries;
82 for (
size_t i = 0; i < filtered_images.size(); ++i) {
86 return {filtered_images, boundaries};
90 const std::vector<int>& param_filt) {
93 input.convertTo(float_img, CV_64F);
98 double r1 =
static_cast<double>(param_filt[0]);
99 double r2 =
static_cast<double>(param_filt[1]);
101 int rows = float_img.rows;
102 int cols = float_img.cols;
105 cv::Mat filter_mask(rows, cols, CV_64F);
109 for (
int y = 0; y < rows; ++y) {
110 for (
int x = 0; x < cols; ++x) {
113 double r_sq = dx * dx + dy * dy;
116 double low_pass = std::exp(-r_sq / (2.0 * r2 * r2));
117 double high_pass = (r1 != 0) ? (1.0 - std::exp(-r_sq / (2.0 * r1 * r1))) : 1.0;
118 filter_mask.at<
double>(y, x) = low_pass * high_pass;
123 cv::Mat planes[] = {float_img, cv::Mat::zeros(float_img.size(), CV_64F)};
125 cv::merge(planes, 2, complex_img);
126 cv::dft(complex_img, complex_img);
129 cv::Mat filter_shifted;
130 int cx2 = filter_mask.cols / 2;
131 int cy2 = filter_mask.rows / 2;
132 cv::Mat q0(filter_mask, cv::Rect(0, 0, cx2, cy2));
133 cv::Mat q1(filter_mask, cv::Rect(cx2, 0, cols - cx2, cy2));
134 cv::Mat q2(filter_mask, cv::Rect(0, cy2, cx2, rows - cy2));
135 cv::Mat q3(filter_mask, cv::Rect(cx2, cy2, cols - cx2, rows - cy2));
138 filter_shifted = cv::Mat(rows, cols, CV_64F);
139 q3.copyTo(filter_shifted(cv::Rect(0, 0, cols - cx2, rows - cy2)));
140 q0.copyTo(filter_shifted(cv::Rect(cols - cx2, rows - cy2, cx2, cy2)));
141 q1.copyTo(filter_shifted(cv::Rect(0, rows - cy2, cols - cx2, cy2)));
142 q2.copyTo(filter_shifted(cv::Rect(cols - cx2, 0, cx2, rows - cy2)));
145 cv::split(complex_img, planes);
146 planes[0] = planes[0].mul(filter_shifted);
147 planes[1] = planes[1].mul(filter_shifted);
148 cv::merge(planes, 2, complex_img);
151 cv::Mat filtered_img;
152 cv::idft(complex_img, filtered_img, cv::DFT_SCALE);
153 cv::split(filtered_img, planes);
159 const cv::Mat& mask) {
162 image.convertTo(float_img, CV_32F);
164 double min_val = std::numeric_limits<double>::max();
165 double max_val = std::numeric_limits<double>::lowest();
167 for (
int y = 0; y < image.rows; ++y) {
168 for (
int x = 0; x < image.cols; ++x) {
169 if (mask.at<uint8_t>(y, x) > 0) {
170 double val = float_img.at<
float>(y, x);
171 min_val = std::min(min_val, val);
172 max_val = std::max(max_val, val);
177 return {min_val, max_val};
182 double lower_percentile,
183 double upper_percentile) {
185 std::vector<double> values;
189 if (image.type() == CV_64F) {
192 image.convertTo(double_img, CV_64F);
195 for (
int y = 0; y < double_img.rows; ++y) {
196 for (
int x = 0; x < double_img.cols; ++x) {
197 if (mask.at<uint8_t>(y, x) > 0) {
198 values.push_back(double_img.at<
double>(y, x));
203 if (values.empty()) {
204 LOG_WARN <<
"No pixels in mask for percentile computation";
209 std::sort(values.begin(), values.end());
212 size_t lower_idx =
static_cast<size_t>(values.size() * lower_percentile / 100.0);
213 size_t upper_idx =
static_cast<size_t>(values.size() * upper_percentile / 100.0);
215 lower_idx = std::min(lower_idx, values.size() - 1);
216 upper_idx = std::min(upper_idx, values.size() - 1);
218 return {values[lower_idx], values[upper_idx]};
222 const std::pair<double, double>& boundaries) {
229 if (image.type() == CV_64F) {
232 image.convertTo(double_img, CV_64F);
236 double range = boundaries.second - boundaries.first;
238 normalized = (double_img - boundaries.first) / range;
240 cv::threshold(normalized, normalized, 1.0, 1.0, cv::THRESH_TRUNC);
241 cv::threshold(normalized, normalized, 0.0, 0.0, cv::THRESH_TOZERO);
243 normalized = cv::Mat::zeros(image.size(), CV_64F);
248 normalized.convertTo(output, CV_8UC1, 255.0);
static std::pair< std::vector< cv::Mat >, std::pair< double, double > > filterLikeBen(const std::vector< cv::Mat > &input, const cv::Mat &mask, const std::vector< int > ¶m_filt, const std::pair< double, double > *gs_boundaries=nullptr)
Filter images like Ben's method Equivalent to filter_like_ben.m in Matlab.