diff --git a/lib/page/login/jc_captcha.dart b/lib/page/login/jc_captcha.dart index 0f623383..6718ac2a 100644 --- a/lib/page/login/jc_captcha.dart +++ b/lib/page/login/jc_captcha.dart @@ -1,12 +1,10 @@ // Copyright 2023 BenderBlog Rodriguez and contributors. // SPDX-License-Identifier: MIT -// http://thispage.tech:9680/jclee1995/flutter-jc-captcha/-/blob/master/lib/src/captcha_plugin_cn.dart // https://juejin.cn/post/7284608063914622995 import 'dart:convert'; import 'dart:io'; -import 'dart:math'; import 'dart:typed_data'; import 'package:dio/dio.dart'; @@ -99,52 +97,95 @@ class SliderCaptchaClientProvider { return result.data["errorCode"] == 1; } - static double? _trySolve(Uint8List puzzleData, Uint8List pieceData) { + static double? _trySolve(Uint8List puzzleData, Uint8List pieceData, + {int border = 24}) { img.Image? puzzle = img.decodeImage(puzzleData); if (puzzle == null) { return null; } - img.Image? piece = img.decodeImage(pieceData); if (piece == null) { return null; } - // note that puzzle and piece have the same height - - int minY = piece.height - 1; - int maxY = 0; - - for (var y = 0; y < piece.height; y++) { - if (piece.getPixel((piece.width * 0.5).floor(), y).a > 0) { - minY = min(minY, y); - maxY = max(maxY, y); + var bbox = _findAlphaBoundingBox(piece); + int xL = bbox[0] + border; + int yT = bbox[1] + border; + int xR = bbox[2] - border; + int yB = bbox[3] - border; + + var widthW = xR - xL; + var heightW = yB - yT; + var widthG = puzzle.width - piece.width + widthW - 1; + + var meanT = _calculateMean(piece, xL, yT, widthW, heightW); + var templateN = _normalizeImage(piece, xL, yT, widthW, heightW, meanT); + + double nccMax = 0; + int xMax = 0; + for (int x = xL + 1; x < widthG - widthW; x += 2) { + var meanW = _calculateMean(puzzle, x, yT, widthW, heightW); + var ncc = _calculateNCC(puzzle, x, yT, widthW, heightW, templateN, meanW); + if (ncc > nccMax) { + nccMax = ncc; + xMax = x; } } - for (var x = 1; x < puzzle.width - 1; x++) { - int matchCount = 0; - - for (var y = minY; y <= maxY; y++) { - var l = _getPixelGrayscale(puzzle.getPixel(x - 1, y)); - var r = _getPixelGrayscale(puzzle.getPixel(x + 1, y)); + return (xMax - xL - 1) / puzzle.width; + } - // find edge - if ((r - l).abs() > 50) { - matchCount++; - } + static List _findAlphaBoundingBox(img.Image image) { + int xL = image.width, yT = image.height, xR = 0, yB = 0; + for (int y = 0; y < image.height; y++) { + for (int x = 0; x < image.width; x++) { + if (image.getPixel(x, y).a != 255) continue; + if (x < xL) xL = x; + if (y < yT) yT = y; + if (x > xR) xR = x; + if (y > yB) yB = y; } + } + return [xL, yT, xR, yB]; + } - if ((matchCount / (maxY - minY + 1.0)) > 0.6) { - return x / puzzle.width; + static double _calculateMean( + img.Image image, int x, int y, int width, int height) { + double sum = 0; + for (int _y = y; _y < y + height; _y++) { + for (int _x = x; _x < x + width; _x++) { + sum += image.getPixel(_x, _y).luminance; } } + return sum / (width * height); + } - return null; + static List _normalizeImage( + img.Image image, int x, int y, int width, int height, double mean) { + var normalized = List.filled(width * height, 0); + for (int _y = 0; _y < height; _y++) { + for (int _x = 0; _x < width; _x++) { + normalized[_y * width + _x] = + image.getPixel(_x + x, _y + y).luminance - mean; + } + } + return normalized; } - static int _getPixelGrayscale(img.Pixel p) { - return (0.2126 * p.r + 0.7152 * p.g + 0.0722 * p.b).round(); + static double _calculateNCC(img.Image window, int x, int y, int width, + int height, List template, double meanW) { + double sumWt = 0; + double sumWw = 0; + var iT = template.iterator; + for (int _y = y; _y < y + height; _y++) { + for (int _x = x; _x < x + width; _x++) { + iT.moveNext(); + double w = window.getPixel(_x, _y).luminance - meanW; + sumWt += w * iT.current; + sumWw += w * w; + } + } + return sumWt / sumWw; } } diff --git a/lib/page/setting/about_page/about_page.dart b/lib/page/setting/about_page/about_page.dart index 430e99f1..c2bd5ae2 100644 --- a/lib/page/setting/about_page/about_page.dart +++ b/lib/page/setting/about_page/about_page.dart @@ -83,7 +83,7 @@ class AboutPage extends StatelessWidget { Developer( "Pairman", "https://avatars.githubusercontent.com/u/18365163", - "开发:成绩信息缓存功能", + "开发:成绩缓存功能和优化滑块算法", "https://github.com/Pairman", ), Developer(