You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
5.3 KiB
C++

#include "adjust_image.h"
#include "image_morphology.h"
#include <opencv2/imgproc.hpp>
#include <cmath>
#include <algorithm>
using namespace std;
static tuple<cv::Mat, int, ShapeInfo> adjust_image_impl(const cv::Mat& img, const ShapeInfo& shapeinfo, int rotate_range) {
int final_angle = 0;
cv::Mat final_img;
int img_h = img.rows;
int img_w = img.cols;
string shapetype = shapeinfo.type;
cv::RotatedRect minAreaRect = shapeinfo.minAreaRect;
cv::Point2f center = minAreaRect.center;
cv::Size2f wh = minAreaRect.size;
double wh_ratio = max(wh.width / wh.height, wh.height / wh.width);
cv::Mat gray;
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
cv::Mat binary;
cv::threshold(gray, binary, 200, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
if (shapetype == "ellipse" || shapetype == "circle") {
binary = wipe_star(binary, minAreaRect);
}
binary = wipe_noise(binary);
ShapeInfo new_shapeinfo = shapeinfo.copy();
cv::Mat fck_gray = wipe_noise_gray(gray);
if (shapetype == "ellipse" || shapetype == "circle") {
fck_gray = my_dilate(fck_gray, cv::Size(16, 16), 1, WHITE_BG);
}
double min_cal = 1e10;
cv::Mat first_M;
int first_angle = 0;
for (int angle = -rotate_range; angle < rotate_range; ++angle) {
cv::Mat M = cv::getRotationMatrix2D(center, angle, 1.0);
cv::Mat fck_gray1;
cv::warpAffine(fck_gray, fck_gray1, M, cv::Size(img_w, img_h), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(255));
int center_x = static_cast<int>(center.x);
center_x = min(max(1, center_x), img_w - 1);
int left_w = center_x;
int right_start = (img_w % 2 == 0) ? center_x : (center_x + 1);
int right_w = img_w - right_start;
int min_w = min(left_w, right_w);
cv::Mat left, right;
if (min_w > 0) {
left = fck_gray1(cv::Rect(0, 0, min_w, img_h)).clone();
cv::Mat right_part = fck_gray1(cv::Rect(right_start, 0, min_w, img_h));
cv::flip(right_part, right, 1);
} else {
left = cv::Mat::zeros(img_h, 1, fck_gray1.type());
right = cv::Mat::zeros(img_h, 1, fck_gray1.type());
}
cv::Mat diff;
cv::absdiff(left, right, diff);
int cal = cv::countNonZero(diff);
if (cal < min_cal) {
min_cal = cal;
first_M = M.clone();
first_angle = angle;
}
}
cv::Mat first_gray;
cv::warpAffine(gray, first_gray, first_M, cv::Size(img_w, img_h), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(255));
final_angle = first_angle;
if (wh_ratio < 1.1 && abs(first_angle) > 45) {
cv::Mat binary2;
cv::threshold(first_gray, binary2, 200, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
int x_range[2] = {static_cast<int>(center.x - wh.width / 2 * 0.4),
static_cast<int>(center.x + wh.width / 2 * 0.4)};
int y_range[2] = {static_cast<int>(center.y - wh.height / 2 * 0.85),
static_cast<int>(center.y + wh.height / 2 * 0.85)};
int tx1 = max(0, x_range[0]);
int ty1 = max(0, y_range[0]);
int tx2 = min(static_cast<int>(first_gray.cols), x_range[1]);
int ty2 = min(static_cast<int>(first_gray.rows), y_range[1]);
if (tx1 < tx2 && ty1 < ty2) {
int range_w = tx2 - tx1;
int range_h = ty2 - ty1;
if (range_w > 0 && range_h > 0) {
cv::Mat hahaha = binary2(cv::Rect(tx1, ty1, range_w, range_h)).clone();
int up_h = max(1, static_cast<int>(hahaha.rows / 4.0));
int down_y = static_cast<int>(hahaha.rows / 4.0 * 3);
down_y = min(max(down_y, 0), hahaha.rows - up_h);
if (up_h > 0 && down_y >= 0 && down_y + up_h <= hahaha.rows) {
cv::Mat up = hahaha(cv::Rect(0, 0, hahaha.cols, up_h)).clone();
cv::Mat down = hahaha(cv::Rect(0, down_y, hahaha.cols, up_h)).clone();
int up_cnt = cv::countNonZero(up);
int down_cnt = cv::countNonZero(down);
double up_div_down = max(up_cnt, down_cnt) / max(1, min(up_cnt, down_cnt));
if (up_div_down > 2) {
if (up_cnt < down_cnt) {
final_angle = first_angle + 180;
}
}
}
}
}
}
cv::Mat final_M = cv::getRotationMatrix2D(center, final_angle, 1);
cv::warpAffine(img, final_img, final_M, cv::Size(img_w, img_h), cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(255, 255, 255));
new_shapeinfo.minAreaRect = cv::RotatedRect(new_shapeinfo.minAreaRect.center,
new_shapeinfo.minAreaRect.size, 0);
return make_tuple(final_img, final_angle, new_shapeinfo);
}
tuple<cv::Mat, int, ShapeInfo> adjust_img(const cv::Mat& img, const ShapeInfo& shapeinfo) {
string shapetype = shapeinfo.type;
if (shapetype == "ellipse" || shapetype == "circle") {
return adjust_image_impl(img, shapeinfo, 90);
} else if (shapetype == "square") {
return adjust_image_impl(img, shapeinfo, 30);
} else {
return make_tuple(img.clone(), 0, shapeinfo.copy());
}
}