Skip to content

Commit ddf65a7

Browse files
authored
Merge pull request #4 from keyurgit45/autozoom
modify zoom algorithm
2 parents 81395f1 + dbf9d16 commit ddf65a7

10 files changed

+300
-185
lines changed
Binary file not shown.

qrscanner/lib/app.dart

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
import 'package:flutter/material.dart';
2-
import 'package:get/get_navigation/src/root/get_material_app.dart';
2+
import 'package:get/get.dart';
33
import 'package:qrscanner/pages/home_page.dart';
4+
import 'package:qrscanner/pages/qr_autozoom.dart';
45

56
class MyApp extends StatelessWidget {
67
const MyApp({super.key});
78

89
@override
910
Widget build(BuildContext context) {
1011
return GetMaterialApp(
11-
home: HomePage(),
12+
initialRoute: '/',
13+
getPages: [
14+
GetPage(name: '/', page: () => HomePage()),
15+
GetPage(
16+
name: '/qrautozoom',
17+
page: () => QRAutozoom(),
18+
transition: Transition.cupertino)
19+
],
1220
);
1321
}
1422
}

qrscanner/lib/controller/camera_view_controller.dart

+59-39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import 'dart:io';
2-
import 'dart:ui';
3-
42
import 'package:camera/camera.dart';
53
import 'package:gallery_saver/gallery_saver.dart';
64
import 'package:get/get.dart';
@@ -11,6 +9,7 @@ import 'package:qrscanner/utils/snackbar.dart';
119

1210
class CameraViewController extends GetxController {
1311
final YOLOController _yoloController = Get.find<YOLOController>();
12+
1413
CameraController? cameraController;
1514
List<CameraDescription>? cameras;
1615
CameraImage? cameraImage;
@@ -20,7 +19,6 @@ class CameraViewController extends GetxController {
2019

2120
var zoomLevel = 1.0.obs;
2221
var maxZoomLevel = 1.0.obs;
23-
2422
var isTakingPicture = false.obs;
2523

2624
@override
@@ -30,32 +28,35 @@ class CameraViewController extends GetxController {
3028
}
3129

3230
Future<void> initializeCamera() async {
33-
cameras = await availableCameras();
34-
if (cameras!.isNotEmpty) {
35-
cameraController = CameraController(
36-
cameras![0],
37-
ResolutionPreset.medium,
38-
imageFormatGroup: Platform.isAndroid
39-
? ImageFormatGroup.yuv420
40-
: ImageFormatGroup.bgra8888,
41-
);
42-
43-
camFrameRotation = Platform.isAndroid ? cameras![0].sensorOrientation : 0;
44-
await cameraController?.initialize().then((_) async {
45-
// Stream of image passed to [onLatestImageAvailable] callback
46-
await cameraController?.startImageStream((CameraImage image) =>
47-
_yoloController.onEachCameraImage(
48-
image, camFrameRotation, setCameraZoomLevel));
49-
50-
logger.i(cameraController!.value.previewSize.toString());
51-
52-
ratio = cameraController!.value.aspectRatio;
53-
54-
logger.i(ratio);
55-
});
56-
maxZoomLevel.value = await cameraController!.getMaxZoomLevel();
57-
logger.i(maxZoomLevel);
58-
update(); // Using update() to rebuild GetBuilder widgets
31+
try {
32+
cameras = await availableCameras(); // check for available cameras
33+
if (cameras!.isNotEmpty) {
34+
cameraController = CameraController(
35+
cameras![0],
36+
ResolutionPreset.medium,
37+
imageFormatGroup: Platform.isAndroid
38+
? ImageFormatGroup.yuv420
39+
: ImageFormatGroup.bgra8888,
40+
);
41+
42+
camFrameRotation =
43+
Platform.isAndroid ? cameras![0].sensorOrientation : 0;
44+
45+
await cameraController?.initialize().then((_) async {
46+
maxZoomLevel.value = await cameraController!.getMaxZoomLevel();
47+
// Stream of image passed to [onLatestImageAvailable] callback
48+
await cameraController?.startImageStream((CameraImage image) async =>
49+
_yoloController.onEachCameraImage(
50+
image, camFrameRotation, setCameraZoomLevel));
51+
52+
ratio = cameraController!.value.aspectRatio;
53+
});
54+
55+
update(); // Using update() to rebuild GetBuilder widgets
56+
}
57+
} catch (e) {
58+
showSnackBar('Error', 'something went wrong!');
59+
logger.log(level, e);
5960
}
6061
}
6162

@@ -69,40 +70,59 @@ class CameraViewController extends GetxController {
6970
if (cameraController!.value.isTakingPicture) {
7071
return;
7172
}
73+
74+
// capture picture
7275
final XFile file = await cameraController!.takePicture();
76+
77+
//save image to gallery
7378
await GallerySaver.saveImage(file.path).then((bool? isSaved) {
7479
if (isSaved ?? false) {
7580
showSnackBar('Success', 'Picture saved to Gallery');
7681
}
7782
});
7883
} on CameraException catch (e) {
7984
showSnackBar('Error', 'something went wrong!');
80-
print(e);
85+
logger.log(level, e);
8186
return;
8287
}
8388
}
8489

90+
/// takes List of predictions and increases or decreases zoom level according to width of the QR code
8591
void setCameraZoomLevel(List<ResultObjectDetection> predictions) async {
8692
double level = zoomLevel.value;
8793

94+
predictions.sort((a, b) =>
95+
b.score.compareTo(a.score)); // sort predictions according to score
96+
8897
if (predictions.isNotEmpty) {
8998
if (predictions.first.rect.width <= 0.8 &&
9099
predictions.first.rect.left >= 0.1 &&
91100
predictions.first.rect.right >= 0.1 &&
92101
predictions.first.rect.top >= 0.1 &&
93102
predictions.first.rect.bottom >= 0.1) {
94-
print(
95-
"Since width is ${predictions.first.rect.width} -> increasing level to ${level + 0.15}");
96-
level += 0.15;
97-
if (level > maxZoomLevel.value) level = maxZoomLevel.value;
98-
} else if (predictions.first.rect.width > 0.9) {
99-
print(
100-
"Since width is ${predictions.first.rect.width} -> decreasing level to ${level - 0.2}");
103+
if (predictions.first.rect.width > 0 &&
104+
predictions.first.rect.width < 0.3) {
105+
level += 0.3;
106+
} else if (predictions.first.rect.width >= 0.3 &&
107+
predictions.first.rect.width < 0.5) {
108+
level += 0.2;
109+
} else if (predictions.first.rect.width >= 0.5 &&
110+
predictions.first.rect.width < 0.7) {
111+
level += 0.15;
112+
} else if (predictions.first.rect.width >= 0.7 &&
113+
predictions.first.rect.width <= 0.75) {
114+
level += 0.1;
115+
}
116+
} else if (predictions.first.rect.width >= 0.9 &&
117+
predictions.first.rect.width < 1.5) {
101118
level -= 0.2;
102-
if (level < 1) level = 1;
103119
}
104120
}
105-
121+
if (level > maxZoomLevel.value) {
122+
level = maxZoomLevel.value;
123+
} else if (level < 1) {
124+
level = 1;
125+
}
106126
if (zoomLevel.value != level) {
107127
zoomLevel.value = level;
108128
await cameraController?.setZoomLevel(level);

qrscanner/lib/controller/yolo_controller.dart

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
import 'dart:io';
2-
import 'dart:typed_data';
31
import 'package:camera/camera.dart';
4-
import 'package:flutter/material.dart';
2+
import 'package:flutter/foundation.dart';
53
import 'package:flutter/services.dart';
64
import 'package:get/get.dart';
75
import 'package:pytorch_lite/pytorch_lite.dart';
86
import 'package:qrscanner/utils/app_logger.dart';
9-
import 'package:image/image.dart' as img;
107
import 'package:qrscanner/utils/snackbar.dart';
118

129
class YOLOController extends GetxController {
1310
ModelObjectDetection? _objectModel;
1411
var isDetecting = false.obs;
1512
var results = Rxn<List<ResultObjectDetection>>([]);
1613
var objectDetectionInferenceTime = Rx<Duration>(Duration.zero);
14+
static const String _modelPath = "assets/bestv2.torchscript";
15+
static const String _labelPath = "assets/labels.txt";
16+
static const int _imgsz = 224; // image size
17+
static const int _numberOfClasses = 1;
18+
static const ObjectDetectionModelType _objectDetectionModelType =
19+
ObjectDetectionModelType.yolov8;
1720

1821
@override
1922
Future<void> onInit() async {
@@ -22,12 +25,12 @@ class YOLOController extends GetxController {
2225
}
2326

2427
Future loadModel() async {
25-
String pathObjectDetectionModel = "assets/bestv2.torchscript";
2628
try {
2729
_objectModel = await PytorchLite.loadObjectDetectionModel(
28-
pathObjectDetectionModel, 1, 224, 224,
29-
labelPath: "assets/labels.txt",
30-
objectDetectionModelType: ObjectDetectionModelType.yolov8);
30+
_modelPath, _numberOfClasses, _imgsz, _imgsz,
31+
labelPath: _labelPath,
32+
objectDetectionModelType: _objectDetectionModelType);
33+
logger.log(level, "Model loaded");
3134
} catch (e) {
3235
if (e is PlatformException) {
3336
showSnackBar("Error", "Only supported for android");
@@ -73,7 +76,7 @@ class YOLOController extends GetxController {
7376

7477
objectDetectionInferenceTime.value = stopwatch.elapsed;
7578
for (var element in results.value!) {
76-
print({
79+
debugPrint({
7780
"rect": {
7881
"left": element.rect.left,
7982
"top": element.rect.top,
@@ -83,7 +86,7 @@ class YOLOController extends GetxController {
8386
"bottom": element.rect.bottom,
8487
"time to process": stopwatch.elapsed
8588
},
86-
});
89+
}.toString());
8790
}
8891

8992
autoZoomToQR(objDetect, setCameraZoomLevel);

qrscanner/lib/pages/camera_view.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ import 'package:qrscanner/controller/camera_view_controller.dart';
55

66
/// Shows camera preview
77
class CameraView extends StatelessWidget {
8+
const CameraView({super.key});
9+
810
@override
911
Widget build(BuildContext context) {
1012
return GetBuilder<CameraViewController>(
1113
init: CameraViewController(),
1214
builder: (controller) {
1315
if (controller.cameraController == null ||
1416
!controller.cameraController!.value.isInitialized) {
15-
return Center(child: CircularProgressIndicator());
17+
return const Center(child: CircularProgressIndicator());
1618
}
1719
return CameraPreview(controller.cameraController!);
1820
},

0 commit comments

Comments
 (0)