81 lines
2.3 KiB
Dart
81 lines
2.3 KiB
Dart
import 'package:opencv_dart/opencv_dart.dart' as cv;
|
|
import '../../domain/entities/quality_result.dart';
|
|
|
|
class QualityChecker {
|
|
|
|
static double getBlurScore(cv.Mat mat) {
|
|
final laplacian = cv.laplacian(mat, cv.MatType.CV_64F);
|
|
final (_, stddev) = cv.meanStdDev(laplacian);
|
|
laplacian.dispose();
|
|
return stddev.val1 * stddev.val1;
|
|
}
|
|
|
|
static double checkIllumination(cv.Mat mat) {
|
|
final meanScalar = cv.mean(mat);
|
|
return meanScalar.val1;
|
|
}
|
|
|
|
static bool checkPosition(cv.Mat mat) {
|
|
final (_, threshMat) = cv.threshold(mat, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU);
|
|
final (contours, hierarchy) = cv.findContours(threshMat, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
|
|
threshMat.dispose();
|
|
hierarchy.dispose();
|
|
|
|
if (contours.isEmpty) return false;
|
|
|
|
double maxArea = 0;
|
|
cv.Rect? maxRect;
|
|
|
|
for (int i = 0; i < contours.length; i++) {
|
|
final contour = contours[i];
|
|
final area = cv.contourArea(contour);
|
|
if (area > maxArea) {
|
|
maxArea = area;
|
|
maxRect = cv.boundingRect(contour);
|
|
}
|
|
}
|
|
|
|
if (maxRect == null) return false;
|
|
|
|
final imgW = mat.cols;
|
|
final imgH = mat.rows;
|
|
|
|
final guideX = imgW ~/ 4;
|
|
final guideY = imgH ~/ 4;
|
|
final guideW = imgW ~/ 2;
|
|
final guideH = imgH ~/ 2;
|
|
|
|
final objCx = maxRect.x + maxRect.width / 2;
|
|
final objCy = maxRect.y + maxRect.height / 2;
|
|
|
|
final bool isCentered = objCx >= guideX && objCx <= (guideX + guideW) &&
|
|
objCy >= guideY && objCy <= (guideY + guideH);
|
|
|
|
final bool isBigEnough = maxArea > (imgW * imgH * 0.25);
|
|
|
|
return isCentered && isBigEnough;
|
|
}
|
|
|
|
static QualityResult analyze(cv.Mat mat) {
|
|
final blur = getBlurScore(mat);
|
|
final brightness = checkIllumination(mat);
|
|
final positionValid = checkPosition(mat);
|
|
|
|
final bool isSharp = blur > 100.0;
|
|
final bool isLit = brightness > 40.0 && brightness < 220.0;
|
|
|
|
final normBlur = (blur / 500.0).clamp(0.0, 1.0);
|
|
final normBright = 1.0 - ((brightness - 128).abs() / 128.0).clamp(0.0, 1.0);
|
|
|
|
final score = (normBlur * 0.6) + (normBright * 0.4);
|
|
|
|
return QualityResult(
|
|
passed: isSharp && isLit && positionValid,
|
|
score: score,
|
|
blurScore: blur,
|
|
brightness: brightness,
|
|
isPositionValid: positionValid,
|
|
);
|
|
}
|
|
}
|