diff --git a/alg/Makefile b/alg/Makefile index 5a230bc..6707ccd 100644 --- a/alg/Makefile +++ b/alg/Makefile @@ -260,6 +260,6 @@ install-scanner: qrtool.wx.wasm.br @cp -v qrtool.wx.js ../scanner/worker install-web: qrtool.web.wasm - @cp -v qrtool.web.js qrtool.web.wasm ../web/public/camera-4.0/js/ + @cp -v qrtool.web.js qrtool.web.wasm ../web/public/camera-5.0/js/ install: install-web install-scanner diff --git a/alg/libqr.cpp b/alg/libqr.cpp index 3fa1c44..e5da78b 100644 --- a/alg/libqr.cpp +++ b/alg/libqr.cpp @@ -111,14 +111,12 @@ bool detect_qr(ProcessState &ps, float margin_ratio, bool warp, string &err) cvtColor(ps.straighten, g, COLOR_BGR2GRAY); equalizeHist(g, g); - Rect dot_rect; - dot_rect.x = 0; - dot_rect.y = 0; - dot_rect.width = margin / 2; - dot_rect.height = margin / 2; - ps.dot_area = ps.straighten(dot_rect); - Mat dot_area_gray = g(dot_rect); - resize(dot_area_gray, ps.dot_area_gray, Size(64, 64)); + Rect left_mid_rect; + left_mid_rect.x = 0; + left_mid_rect.y = ps.straighten.rows / 6; + left_mid_rect.width = ps.straighten.cols / 3; + left_mid_rect.height = ps.straighten.rows / 3; + ps.left_mid_area = ps.straighten(left_mid_rect); return true; } @@ -138,107 +136,6 @@ bool preprocess(ProcessState &ps) return true; } -struct EnergyGradient { - double x; - double y; -}; - -static -EnergyGradient energy_gradient(Mat &gray_img) -{ - - Mat smd_image_x, smd_image_y, G; - - Mat kernel_x(3, 3, CV_32F, Scalar(0)); - kernel_x.at(1, 2) = -1.0; - kernel_x.at(1, 1) = 1.0; - Mat kernel_y(3, 3, CV_32F, Scalar(0)); - kernel_y.at(1, 1) = 1.0; - kernel_y.at(2, 1) = -1.0; - filter2D(gray_img, smd_image_x, gray_img.depth(), kernel_x); - filter2D(gray_img, smd_image_y, gray_img.depth(), kernel_y); - - multiply(smd_image_x, smd_image_x, smd_image_x); - multiply(smd_image_y, smd_image_y, smd_image_y); - - EnergyGradient ret = { mean(smd_image_x)[0], mean(smd_image_y)[0], }; - return ret; -} - -static -bool check_blur_by_energy_gradient(Mat &gray, string &err) -{ - const int thres = 85; - auto a = energy_gradient(gray); - - float angle = 45; - auto m = getRotationMatrix2D(Point2f(gray.cols / 2, gray.rows / 2), angle, 1.0); - Mat rotated; - warpAffine(gray, rotated, m, gray.size()); - - auto b = energy_gradient(rotated); - - auto diffa = fabs(a.x - a.y); - auto diffb = fabs(b.x - b.y); - auto diffa_percent = 100 * diffa / max(a.x, a.y); - auto diffb_percent = 100 * diffb / max(b.x, b.y); - bool ret = - ((a.x > thres && a.y > thres) || (b.x > thres && b.y > thres)) && - diffa_percent < 15 && diffb_percent < 15; - - cout << "energy: " - + to_string(a.x) + " " - + to_string(a.y) + " " - + to_string(b.x) + " " - + to_string(b.y) << endl; - if (!ret) { - err = "energy: " - + to_string(a.x) + " " - + to_string(a.y) + " " - + to_string(b.x) + " " - + to_string(b.y); - } - - return ret; -} - -double laplacian(Mat &gray, string &err) -{ - int ddepth = CV_16S; - Mat check, lap; - GaussianBlur(gray, check, Size(5, 5), 0, 0, BORDER_DEFAULT); - Laplacian(check, lap, ddepth, 3); - convertScaleAbs(lap, lap); - - Mat mean, stddev; - meanStdDev(lap, mean, stddev); - if (stddev.cols * stddev.rows == 1) { - double area = gray.rows * gray.cols; - double sd = stddev.at(0, 0); - double var = sd * sd; - return var / area; - } - err = "wrong shape of stddev result"; - return -1; -} - -static -bool check_blur_by_laplacian(ProcessState &ps, Mat &gray, string &err) -{ - auto var = laplacian(gray, err); - if (var < 0) return false; - - ps.clarity = var; - if (var <= ps.laplacian_thres) { - err = string_format("image (%d x %d) too blurry: %lf <= %lf", - gray.cols, gray.rows, - var, ps.laplacian_thres - ); - return false; - } - return true; -} - static bool check_blur_by_sobel(ProcessState &ps, Mat &gray, string &err) { @@ -253,6 +150,7 @@ bool check_blur_by_sobel(ProcessState &ps, Mat &gray, string &err) Scalar meanMagnitude = mean(magnitude); double sharpness = meanMagnitude[0] / (gray.rows * gray.cols) * 1000; + ps.clarity = sharpness; if (sharpness < thres) { err = string_format("image too blurry: %lf < %lf", sharpness, thres); return false; @@ -286,151 +184,6 @@ static bool is_valid_pattern(Mat &img) } #endif -static -int find_score(Mat &img) -{ - int ret = 0; - for (int row = 0; row < img.rows; row++) { - int row_sum = 0; - for (int col = 0; col < img.cols; col++) { - auto p = img.at(row, col); - if (p) { - row_sum += 1; - } - } - if (row_sum) { - ret += 1; - } - } - return ret; -} - -static void clear_connected(Mat &bin, Point p) -{ - vector q; - q.push_back(p); - while (q.size()) { - auto p = q[q.size() - 1]; - q.pop_back(); - bin.at(p.y, p.x) = 0; - for (int i = -1; i <= 1; i++) { - for (int j = -1; j <= 1; j++) { - int nx = p.x + i; - int ny = p.y + j; - if (nx < 0 || nx >= bin.cols || ny < 0 || ny >= bin.rows) { - continue; - } - if (bin.at(ny, nx)) { - q.push_back(Point(nx, ny)); - } - } - } - } -} - -static -vector find_points(Mat bin) -{ - vector ret; - for (int x = 0; x < bin.cols; x++) { - for (int y = 0; y < bin.rows; y++) { - auto p = bin.at(y, x); - if (!p) continue; - auto point = Point(x, y); - ret.push_back(point); - clear_connected(bin, point); - } - } - return ret; -} - -static -int adaptive_erode(Mat &bin, Mat &eroded, string &err) -{ - auto kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3)); - const int min_points = 25; - int max_erodes = 5; - - printf("adaptiveThreshold\n"); - eroded = bin.clone(); - while (max_erodes-- > 0) { - // In this loop we erode a "full" image in order to get enough detached components - auto points = find_points(bin.clone()); - printf("points: %zu\n", points.size()); - if (points.size() == 0) { - err = "cannot find enough points"; - return -1; - } - if (points.size() > min_points) { - break; - } - erode(eroded, eroded, kernel); - } - - while (max_erodes-- > 0) { - // In this loop we further erode a "lean" image in order to get clarity until it's too much - Mat next; - erode(eroded, next, kernel); - auto points = find_points(next.clone()); - if (points.size() < min_points) { - break; - } - eroded = next; - } - - return 0; -} - -static -int emblem_detect_angle(Mat &gray, bool check_orthogonal, string &err) -{ - Mat bin; - int min_score = gray.cols; - int max_score = 0; - int lowest_score_angle = -1; - - adaptiveThreshold(gray, bin, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 11, 2); - - Mat inverted; - bitwise_not(bin, inverted); - const int MAX_ROT_ANGLE = 180; - int scores[MAX_ROT_ANGLE] = { 0 }; - const int score_diff_thres = 5; - - Mat eroded; - adaptive_erode(bin, eroded, err); - - for (int angle = 0; angle < MAX_ROT_ANGLE; angle += 1) { - auto m = getRotationMatrix2D(Point2f(gray.cols / 2, gray.rows / 2), angle, 1.0); - Mat rotated; - warpAffine(eroded, rotated, m, gray.size()); - int score = find_score(rotated); - scores[angle] = score; - if (score < min_score) { - lowest_score_angle = angle; - } - min_score = min(score, min_score); - max_score = max(max_score, score); - } - if (max_score - min_score > score_diff_thres) { - int orthogonal_angle = lowest_score_angle + 90; - if (orthogonal_angle > 180) { - orthogonal_angle -= 180; - } - int orthogonal_score = scores[orthogonal_angle]; - printf("lowest_score_angle %d, min score %d, max score %d, orthogonal_angle %d, orthogonal score: %d\n", - lowest_score_angle, min_score, max_score, orthogonal_angle, orthogonal_score); - lowest_score_angle = lowest_score_angle > 90 ? lowest_score_angle - 90 : lowest_score_angle; - if (lowest_score_angle > 45) - lowest_score_angle = 90 - lowest_score_angle; - if (max_score - orthogonal_score > score_diff_thres || !check_orthogonal) { - return lowest_score_angle; - } - } - - return -1; -} - bool emblem_dot_angle(ProcessState &ps, InputArray in, float &angle, string &qrcode, string &err) { try { @@ -438,7 +191,7 @@ bool emblem_dot_angle(ProcessState &ps, InputArray in, float &angle, string &qrc ps.orig = (Mat *)in.getObj(); preprocess(ps); - if (!detect_qr(ps, 0.20, true, err)) { + if (!detect_qr(ps, 0, true, err)) { qrcode = ps.qrcode; err = "detect_qr: " + err; return false; @@ -446,7 +199,9 @@ bool emblem_dot_angle(ProcessState &ps, InputArray in, float &angle, string &qrc qrcode = ps.qrcode; - if (!check_sharpness(ps, ps.dot_area_gray, ps.sharpness_method, err)) { + Mat lma_gray; + cvtColor(ps.left_mid_area, lma_gray, COLOR_BGR2GRAY); + if (!check_sharpness(ps, lma_gray, ps.sharpness_method, err)) { return false; } diff --git a/alg/libqr.h b/alg/libqr.h index bd69077..ce87878 100644 --- a/alg/libqr.h +++ b/alg/libqr.h @@ -20,13 +20,11 @@ struct ProcessState { CvImg straighten; Rect qr_rect_in_straighten; CvImg qr_straighten; - CvImg dot_area; - CvImg dot_area_gray; + CvImg left_mid_area; string qrcode = ""; - double clarity; - float laplacian_thres = 0.1; float sobel_thres = 15; int sharpness_method = 2; + float clarity = 0; }; bool preprocess(ProcessState &ps); @@ -37,7 +35,6 @@ enum SimilarityAlg { FuzzyPixelCmp, }; double emblem_roi_similarity(SimilarityAlg alg, InputArray a, InputArray b, string &err); -double laplacian(Mat &gray, string &err); static inline void showimg_(const char *title, Mat &img) { imshow(title, img); diff --git a/alg/qrtool.cpp b/alg/qrtool.cpp index a7c7e9d..f1bdd35 100644 --- a/alg/qrtool.cpp +++ b/alg/qrtool.cpp @@ -81,218 +81,10 @@ int dot_cmd(char **argv, int argc) printf("angle: %.1f\n", angle); printf("qrcode: %s\n", qrcode.c_str()); printf("saving dot file: %s\n", outfile.c_str()); - imwrite(outfile, ps.dot_area); + imwrite(outfile, ps.left_mid_area); return 0; } -static -int clarity_cmd(char **argv, int argc) -{ - string err; - - char *file = argv[0]; - printf("file: %s\n", file); - Mat orig = imread(file); - Mat gray; - cvtColor(orig, gray, COLOR_BGR2GRAY); - auto c = laplacian(gray, err); - printf("clarity: %lf\n", c); - - return 0; -} - -static -int rectify_cmd(char **argv, int argc) -{ - char *file = argv[0]; - string err; - ProcessState ps; - Mat orig = imread(file); - - ps.orig = &orig; - preprocess(ps); - - if (!detect_qr(ps, 0.20, false, err)) { - cerr << err << endl; - return 1; - } - string outfile = string(file) + ".qr.jpg"; - imwrite(outfile, ps.straighten); - return 0; -} - -static -int topleft_cmd(char **argv, int argc) -{ - char *file = argv[0]; - string err; - ProcessState ps; - Mat orig = imread(file); - - ps.orig = &orig; - preprocess(ps); - - if (!detect_qr(ps, 0.02, true, err)) { - cerr << err << endl; - return 1; - } - string outfile = string(file) + ".topleft.jpg"; - Mat &base = ps.straighten; - auto crop = Rect(0, 0, base.cols / 2, base.rows / 2); - Mat result = base(crop); - imwrite(outfile, result); - return 0; -} - -static -int find_roi_start_point(Mat &bin, Point &p) -{ - int npoints = 4; - - for (int i = 0; i < bin.cols / 3; i++) { - uchar sum = 0; - for (int j = 0; j < npoints; j++) { - int v = i + j; - sum += bin.at(v, v); - } - if (sum == 0) { - p = Point(i, i); - return 0; - } - } - cerr << "find_roi_start_point" << endl; - return -1; -} - -static -vector count_black(Mat &bin, bool count_rows, int size) -{ - vector ret; - for (int i = 0; i < size; i++) { - int count = 0; - for (int j = 0; j < size; j++) { - int x = count_rows ? j : i; - int y = count_rows ? i : j; - if (bin.at(y, x) == 0) count++; - } - ret.push_back(count); - } - return ret; -} - -static int find_start_of_first_black_range(const vector &data) -{ - size_t i = 0; - int m = *std::max_element(data.begin(), data.end()); - int thres = m * 50 / 100; - while (i < data.size() - 3) { - if (data[i] >= thres && data[i + 1] >= thres && data[i + 2] >= thres) { - break; - } - i++; - } - if (i >= data.size() - 3) return -1; - return i; -} - -static int find_end_of_first_black_range(const vector &data) -{ - size_t i = 0; - int m = *std::max_element(data.begin(), data.end()); - int thres = m * 50 / 100; - while (i < data.size() - 3) { - if (data[i] >= thres && data[i + 1] >= thres && data[i + 2] >= thres) { - break; - } - i++; - } - if (i >= data.size() - 3) return -1; - while (i < data.size() - 3) { - if (data[i] < thres || data[i + 1] < thres || data[i + 2] < thres) { - break; - } - i++; - } - if (i >= data.size() - 3) return -1; - return i; -} - -static -int find_roi_rect(Mat &bin, Point &start, Rect &rect, bool inner, string &err) -{ - Mat visited; - bin.copyTo(visited); - vector q; - q.push_back(start); - int min_x = bin.rows, min_y = bin.rows, max_x = 0, max_y = 0; - int orig_size = max(bin.rows, bin.cols); - - while (q.size()) { - Point p = q.back(); - q.pop_back(); - visited.at(p.y, p.x) = 255; - min_x = min(min_x, p.x); - min_y = min(min_y, p.y); - max_x = max(max_x, p.x); - max_y = max(max_y, p.y); - for (int xoff = -1; xoff <= 1; xoff++) { - for (int yoff = -1; yoff <= 1; yoff++) { - int x = p.x + xoff; - int y = p.y + yoff; - if (x >= 0 && x < visited.cols && y >= 0 && y < visited.rows) { - auto v = visited.at(y, x); - if (v == 0) { - if (q.size() >= 20000) { - err = string("roi detected range too large: ") + to_string(q.size()); - return -1; - } - q.push_back(Point(x, y)); - visited.at(y, x) = 255; - } - } - } - } - } - if (max_x - min_x < 50 || max_y - min_y < 50) { - err = "detected roi outer region too small"; - return -1; - } - - auto size = std::max(max_x, max_y); - - auto row_sums = count_black(bin, true, size); - auto col_sums = count_black(bin, false, size); - - min_x = inner ? find_end_of_first_black_range(col_sums) : find_start_of_first_black_range(col_sums); - min_y = inner ? find_end_of_first_black_range(row_sums) : find_start_of_first_black_range(row_sums); - - if (min_x < 0 || min_y < 0) { - err = "min_x or min_y is negative"; - return -1; - } - - // find the max values, similarly - std::reverse(col_sums.begin(), col_sums.end()); - std::reverse(row_sums.begin(), row_sums.end()); - max_x = size - (inner ? find_end_of_first_black_range(col_sums) : find_start_of_first_black_range(col_sums)); - max_y = size - (inner ? find_end_of_first_black_range(row_sums) : find_start_of_first_black_range(row_sums)); - - if (max_x < 0 || max_y < 0) return -1; - - if (max_x - min_x < 50 || max_y - min_y < 50) { - err = "detected roi region too small"; - return -1; - } - size = (max_x - min_x + max_y - min_y) / 2; - - if (size < orig_size / 5 || size > orig_size * 3 / 5) { - err = "size of found region is out of valid range"; - return -1; - } - rect = Rect(min_x + 1, min_y + 1, size, size); - - return 0; -} static void get_bin(Mat &orig, Mat &out) { @@ -307,297 +99,6 @@ static void get_bin(Mat &orig, Mat &out) threshold(gray, out, 128, 255, THRESH_BINARY); } -static -int find_roi(Mat &qr_straighten, Mat &roi, bool inner, string &err) -{ - Mat bin; - Rect topleft_r(0, 0, qr_straighten.cols / 2, qr_straighten.rows / 2); - Mat topleft = qr_straighten(topleft_r); - get_bin(topleft, bin); - - Point start; - Rect roi_rect; - auto r = find_roi_start_point(bin, start); - if (r) { - err = "failed to find roi start point"; - return r; - } - r = find_roi_rect(bin, start, roi_rect, inner, err); - if (r) { - return r; - } - roi = qr_straighten(roi_rect); - return 0; -} - -int roi_process_one(const char *file, bool inner, string &err, bool warp, Mat *roi_out) -{ - Mat roi; - Mat orig = imread(file, IMREAD_COLOR); - Mat qr_with_margin; - - if (warp) { - ProcessState ps; - ps.orig = &orig; - preprocess(ps); - if (!detect_qr(ps, 0.02, true, err)) { - cerr << err << ":" << file << endl; - return 1; - } - qr_with_margin = ps.straighten; - } else { - qr_with_margin = orig; - } - if (qr_with_margin.cols <= 0 || qr_with_margin.rows <= 0) return -1; - auto r = find_roi(qr_with_margin, roi, inner, err); - if (r) return r; - if (roi_out) { - *roi_out = roi; - } - return 0; -} - -static bool is_dir(char *path) -{ - struct stat st; - - if (lstat(path, &st) == 0) { - if (S_ISREG(st.st_mode)) { - return false; - } else if (S_ISDIR(st.st_mode)) { - return true; - } else { - return false; - } - } else { - perror("Error in lstat"); - } - return false; -} - -static void save_roi(string orig_file, Mat &roi) -{ - string outfile = orig_file + ".roi.jpg"; - cout << "save: " << outfile << endl; - imwrite(outfile, roi); -} - -static -int frame_roi_cmd(char **argv, int argc) -{ - char *file = argv[0]; - string err; - int ret = 0; - Mat roi; - - cout << "frame roi processing: " << file << endl; - ret = roi_process_one(file, false, err, true, &roi); - if (ret) { - cerr << "failed to process: " << file << ":" << err < duration = end - begin; - float seconds = duration.count(); - printf("qps: %.1f\n", n / seconds); - return 0; -} - -#if USE_PULSAR -static vector split_path(const string &path) -{ - vector ret; - string cur = ""; - for (auto x: path) { - if (x == '/') { - if (cur.size()) { - ret.push_back(cur); - cur = ""; - } - } else { - cur += x; - } - } - if (cur.size()) { - ret.push_back(cur); - cur = ""; - } - return ret; -} - -static string join_path(const vector fs) -{ - string ret; - const string sep = "/"; - - for (auto x: fs) { - ret += sep + x; - } - if (ret.size() == 0) ret = "/"; - return ret; -} - -static string get_output_path(const string &path) -{ - auto ret = split_path(path); - ret[3] = "roi"; - return join_path(ret); -} - -static -int roi_worker_handle_image(const string &input_path, - const vector &input, - string &output_path, - vector &output) -{ - Mat roi; - Mat orig = imdecode(input, IMREAD_COLOR); - - auto r = find_roi(orig, roi, true, true); - if (r) return r; - imencode(".jpg", roi, output); - output_path = get_output_path(input_path); - return 0; -} - -static -int roi_worker_handle_image_nop(const string &input_path, - const vector &input, - string &output_path, - vector &output) -{ - output.push_back('f'); - output.push_back('o'); - output.push_back('o'); - output_path = get_output_path(input_path); - return 0; -} - -static -int roi_worker_cmd(char *topic) -{ - string worker_name = "roi-worker-"; - worker_name += to_string(rand()); - return mq_worker(topic, "roi-worker", roi_worker_handle_image); -} - -static -int roi_worker_nop_cmd(char *topic) -{ - string worker_name = "roi-worker-"; - worker_name += to_string(rand()); - return mq_worker(topic, "roi-worker", roi_worker_handle_image_nop); -} - -#endif - -#if ENABLE_GRPC -static -int grpc_server_cmd(char *addr) -{ - return run_server(addr, roi_worker_handle_image); -} -#endif - -static -int http_server_handle_image(const vector &input, - vector &output) -{ - string err; - Mat roi; - Mat orig = imdecode(input, IMREAD_COLOR); - - if (orig.empty()) { - return -EINVAL; - } - auto r = find_roi(orig, roi, false, err); - if (r) return r; - imencode(".jpg", roi, output); - return 0; -} - -static -int http_server_cmd(char **argv, int argc) -{ - char *port = argv[0]; - return start_http_server(atoi(port), http_server_handle_image); -} - -static -int verify_cmd(char **args, int nargs) -{ - char *std_file = args[0]; - char *frame_file = args[1]; - Mat std = imread(std_file); - Mat frame = imread(frame_file); - Mat roi; - int r; - - string err; - r = roi_process_one(frame_file, false, err, true, &roi); - if (r) { - printf("failed to find roi: %s\n", err.c_str()); - return r; - } - double s = emblem_roi_similarity(FuzzyPixelCmp, std, roi, err); - - if (err.size()) { - printf("err: %s\n", err.c_str()); - return 1; - } else { - printf("similarity: %f\n", s); return 0; - return 0; - } -} - static void usage(const char *name, vector &cmds) { @@ -634,28 +135,6 @@ int roi_verify_cmd(char **argv, int argc) return 0; } -static -int side_by_side_cmd(char **argv, int argc) -{ - Mat frame_roi; - string err; - cout << "side by side processing: " << argv[0] << " " << argv[1] << endl; - int r = roi_process_one(argv[0], false, err, true, &frame_roi); - if (r) { - cerr << "failed to process: " << argv[0] << ":" << err << endl; - return r; - } - Mat std_roi = imread(argv[1]); - Mat side_by_side; - auto roi_size = Size(128, 128); - resize(frame_roi, frame_roi, roi_size); - resize(std_roi, std_roi, roi_size); - hconcat(frame_roi, std_roi, side_by_side); - auto fn = string(argv[0]) + ".side_by_side.jpg"; - imwrite(fn, side_by_side); - return 0; -} - #ifdef QRTOOL_MAIN int main(int argc, char *argv[]) { @@ -673,24 +152,6 @@ int main(int argc, char *argv[]) add_cmd(detect, 1); add_cmd(angle, 1); - add_cmd(dot, 1); - add_cmd(clarity, 1); - add_cmd(rectify, 1); - add_cmd(topleft, 1); - add_cmd(frame_roi, 1); - add_cmd(roi, 1); - add_cmd(roi_bench, 1); -#if USE_PULSAR - add_cmd(roi_worker, 1); - add_cmd(roi_worker_nop, 1); -#endif -#if ENABLE_GRPC - add_cmd(grpc_server, 1); -#endif - add_cmd(http_server, 1); - add_cmd(verify, 2); - add_cmd(roi_verify, 2); - add_cmd(side_by_side, 2); usage(argv[0], cmds); return 1; } diff --git a/alg/qrtool_wasm.cpp b/alg/qrtool_wasm.cpp index 88910a4..b1255e8 100644 --- a/alg/qrtool_wasm.cpp +++ b/alg/qrtool_wasm.cpp @@ -8,13 +8,14 @@ using namespace cv; using namespace std; static -std::string make_resp(bool ok, string err, int angle = -1, string qrcode = "", double elapsed = 0) +std::string make_resp(bool ok, string err, float clarity, int angle = -1, string qrcode = "", double elapsed = 0) { char buf[512]; - snprintf(buf, sizeof(buf), R"({ "ok": %s, "err": "%s", "qrcode": "%s", "angle": %d, "elapsed": %lf })", + snprintf(buf, sizeof(buf), R"({ "ok": %s, "err": "%s", "qrcode": "%s", "clarity": %lf, "angle": %d, "elapsed": %lf })", ok ? "true" : "false", err.c_str(), qrcode.c_str(), + clarity, angle, elapsed ); @@ -25,35 +26,28 @@ std::string make_resp(bool ok, string err, int angle = -1, string qrcode = "", d extern "C" { const char *qrtool_angle(uint8_t *data, int width, int height, - uint8_t *dot_area, + uint8_t *mid_left_area, float camera_sensitivity) { ProcessState ps; - ps.laplacian_thres = camera_sensitivity / 10.0; - ps.sobel_thres = camera_sensitivity * 15; + ps.sobel_thres = camera_sensitivity * 3; auto start = std::chrono::system_clock::now(); static char ret[512]; - printf("qrtool_angle, width: %d height %d\n", width, height); - for (int i = 0; i < 16; i++) { - printf("%d ", data[i]); - } - printf("\n"); Mat orig(Size(width, height), CV_8UC4, data); - printf("mat: %d %d\n", orig.cols, orig.rows); string qrcode, err; float angle; auto ok = emblem_dot_angle(ps, orig, angle, qrcode, err); auto end = std::chrono::system_clock::now(); std::chrono::duration elapsed = end-start; - auto x = make_resp(ok, err, angle, qrcode, elapsed.count()); - if (dot_area) { - if (!ps.dot_area.empty()) { - Mat da; - ps.dot_area.convertTo(da, CV_8UC4); - resize(da, da, Size(32 ,32)); - memset(dot_area, 255, 32 * 32 * 4); - memcpy(dot_area, da.ptr(), 32 * 32 * 4); + auto x = make_resp(ok, err, ps.clarity, angle, qrcode, elapsed.count()); + if (mid_left_area) { + if (!ps.left_mid_area.empty()) { + Mat lma; + ps.left_mid_area.convertTo(lma, CV_8UC4); + resize(lma, lma, Size(32 ,32)); + memset(mid_left_area, 255, 32 * 32 * 4); + memcpy(mid_left_area, lma.ptr(), 32 * 32 * 4); } else { - memset(dot_area, 55, 32 * 32 * 4); + memset(mid_left_area, 55, 32 * 32 * 4); } } snprintf(ret, 512, "%s", x.c_str()); diff --git a/scanner/assets/qrtool.wx.js b/scanner/assets/qrtool.wx.js index 93dc3c0..3fdca7c 100644 --- a/scanner/assets/qrtool.wx.js +++ b/scanner/assets/qrtool.wx.js @@ -3893,7 +3893,7 @@ var asmLibraryArg = { "y": ___cxa_begin_catch, "wb": ___cxa_current_primary_exception, "Ja": ___cxa_decrement_exception_refcount, - "F": ___cxa_end_catch, + "G": ___cxa_end_catch, "b": ___cxa_find_matching_catch_2, "n": ___cxa_find_matching_catch_3, "C": ___cxa_find_matching_catch_4, @@ -3970,7 +3970,7 @@ var asmLibraryArg = { "g": invoke_vii, "l": invoke_viid, "lb": invoke_viidf, - "G": invoke_viididii, + "F": invoke_viididii, "bb": invoke_viidiiid, "W": invoke_viidiiiii, "Pa": invoke_viifff, @@ -3990,7 +3990,7 @@ var asmLibraryArg = { "pa": invoke_viiifii, "k": invoke_viiii, "M": invoke_viiiid, - "db": invoke_viiiidd, + "cb": invoke_viiiidd, "kb": invoke_viiiidi, "ya": invoke_viiiidid, "Ba": invoke_viiiidiidiiiiiii, @@ -4025,7 +4025,7 @@ var asmLibraryArg = { "ga": invoke_viiiiiiiiiifii, "O": invoke_viiiiiiiiiii, "wa": invoke_viiiiiiiiiiiii, - "cb": invoke_viiiiiiiiiiiiii, + "db": invoke_viiiiiiiiiiiiii, "ba": invoke_viiiiiiiiiiiiiii, "Ta": invoke_viiiiiiiiiiiiiiii, "gb": invoke_viiiiiiiiiiiiiiiiiiidi, @@ -4233,17 +4233,6 @@ function invoke_vii(index, a1, a2) { } } -function invoke_i(index) { - var sp = stackSave(); - try { - return getWasmTableEntry(index)(); - } catch (e) { - stackRestore(sp); - if (e !== e + 0 && e !== "longjmp") throw e; - _setThrew(1, 0); - } -} - function invoke_iifii(index, a1, a2, a3, a4) { var sp = stackSave(); try { @@ -4277,6 +4266,17 @@ function invoke_viiid(index, a1, a2, a3, a4) { } } +function invoke_i(index) { + var sp = stackSave(); + try { + return getWasmTableEntry(index)(); + } catch (e) { + stackRestore(sp); + if (e !== e + 0 && e !== "longjmp") throw e; + _setThrew(1, 0); + } +} + function invoke_viidf(index, a1, a2, a3, a4) { var sp = stackSave(); try { @@ -4772,10 +4772,10 @@ function invoke_viiiiiiiiiddi(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a1 } } -function invoke_viiiidd(index, a1, a2, a3, a4, a5, a6) { +function invoke_viiiiiiiiiiiiii(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) { var sp = stackSave(); try { - getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6); + getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } catch (e) { stackRestore(sp); if (e !== e + 0 && e !== "longjmp") throw e; @@ -4783,10 +4783,10 @@ function invoke_viiiidd(index, a1, a2, a3, a4, a5, a6) { } } -function invoke_viiiiiiiiiiiiii(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) { +function invoke_viiiidd(index, a1, a2, a3, a4, a5, a6) { var sp = stackSave(); try { - getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); + getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6); } catch (e) { stackRestore(sp); if (e !== e + 0 && e !== "longjmp") throw e; diff --git a/scanner/assets/qrtool.wx.wasm.br b/scanner/assets/qrtool.wx.wasm.br index 548f9f2..0428707 100755 Binary files a/scanner/assets/qrtool.wx.wasm.br and b/scanner/assets/qrtool.wx.wasm.br differ diff --git a/scanner/worker/qrtool.wx.js b/scanner/worker/qrtool.wx.js index 93dc3c0..3fdca7c 100644 --- a/scanner/worker/qrtool.wx.js +++ b/scanner/worker/qrtool.wx.js @@ -3893,7 +3893,7 @@ var asmLibraryArg = { "y": ___cxa_begin_catch, "wb": ___cxa_current_primary_exception, "Ja": ___cxa_decrement_exception_refcount, - "F": ___cxa_end_catch, + "G": ___cxa_end_catch, "b": ___cxa_find_matching_catch_2, "n": ___cxa_find_matching_catch_3, "C": ___cxa_find_matching_catch_4, @@ -3970,7 +3970,7 @@ var asmLibraryArg = { "g": invoke_vii, "l": invoke_viid, "lb": invoke_viidf, - "G": invoke_viididii, + "F": invoke_viididii, "bb": invoke_viidiiid, "W": invoke_viidiiiii, "Pa": invoke_viifff, @@ -3990,7 +3990,7 @@ var asmLibraryArg = { "pa": invoke_viiifii, "k": invoke_viiii, "M": invoke_viiiid, - "db": invoke_viiiidd, + "cb": invoke_viiiidd, "kb": invoke_viiiidi, "ya": invoke_viiiidid, "Ba": invoke_viiiidiidiiiiiii, @@ -4025,7 +4025,7 @@ var asmLibraryArg = { "ga": invoke_viiiiiiiiiifii, "O": invoke_viiiiiiiiiii, "wa": invoke_viiiiiiiiiiiii, - "cb": invoke_viiiiiiiiiiiiii, + "db": invoke_viiiiiiiiiiiiii, "ba": invoke_viiiiiiiiiiiiiii, "Ta": invoke_viiiiiiiiiiiiiiii, "gb": invoke_viiiiiiiiiiiiiiiiiiidi, @@ -4233,17 +4233,6 @@ function invoke_vii(index, a1, a2) { } } -function invoke_i(index) { - var sp = stackSave(); - try { - return getWasmTableEntry(index)(); - } catch (e) { - stackRestore(sp); - if (e !== e + 0 && e !== "longjmp") throw e; - _setThrew(1, 0); - } -} - function invoke_iifii(index, a1, a2, a3, a4) { var sp = stackSave(); try { @@ -4277,6 +4266,17 @@ function invoke_viiid(index, a1, a2, a3, a4) { } } +function invoke_i(index) { + var sp = stackSave(); + try { + return getWasmTableEntry(index)(); + } catch (e) { + stackRestore(sp); + if (e !== e + 0 && e !== "longjmp") throw e; + _setThrew(1, 0); + } +} + function invoke_viidf(index, a1, a2, a3, a4) { var sp = stackSave(); try { @@ -4772,10 +4772,10 @@ function invoke_viiiiiiiiiddi(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a1 } } -function invoke_viiiidd(index, a1, a2, a3, a4, a5, a6) { +function invoke_viiiiiiiiiiiiii(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) { var sp = stackSave(); try { - getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6); + getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } catch (e) { stackRestore(sp); if (e !== e + 0 && e !== "longjmp") throw e; @@ -4783,10 +4783,10 @@ function invoke_viiiidd(index, a1, a2, a3, a4, a5, a6) { } } -function invoke_viiiiiiiiiiiiii(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) { +function invoke_viiiidd(index, a1, a2, a3, a4, a5, a6) { var sp = stackSave(); try { - getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); + getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6); } catch (e) { stackRestore(sp); if (e !== e + 0 && e !== "longjmp") throw e;