Skip to content

update captcha solving algo #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 69 additions & 28 deletions lib/page/login/jc_captcha.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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<int> _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<double> _normalizeImage(
img.Image image, int x, int y, int width, int height, double mean) {
var normalized = List<double>.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<double> 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;
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/page/setting/about_page/about_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class AboutPage extends StatelessWidget {
Developer(
"Pairman",
"https://avatars.githubusercontent.com/u/18365163",
"开发:成绩信息缓存功能",
"开发:成绩缓存功能和优化滑块算法",
"https://github.com/Pairman",
),
Developer(
Expand Down