QRVision
— is a web service for scanning QR codes, where the frontend interacts with an operator to capture an image through the camera, and the backend processes this image and tries to extract data from the QR codes into a database.
This section is meant to introduce you to the basics of getting started with the "QRVision" project. Let's go through the details step-by-step:
- Python 3.10: Make sure you have Python 3.10 installed on your machine. You can download it from the official Python website.
- Node.js: Ensure you have Node.js installed for managing frontend dependencies. Download it from the Node.js website.
- Poetry: Install Poetry, which is used for managing Python dependencies. You can install it by running:
Setting Up the Backend:
curl -sSL https://install.python-poetry.org | python3 -
- Clone the repository:
git clone https://github.com/Solrikk/QRVision.git
cd QRVision
- Install Python dependencies:
poetry install
Setting Up the Frontend:
- Navigate to the static directory:
cd static
- Install Node.js dependencies (if any, otherwise skip):
npm install
- Serve the frontend (if needed, otherwise skip): There are no specific commands for serving frontend files here since Flask serves the static files. Ensure Flask is running to serve the frontend.
Running the Application:
- Access the application: Open your web browser and navigate to http://127.0.0.1:5000. You should see the main application interface.
- Using the QR Scanner:
- Allow access to your webcam when prompted.
- Position a QR code within the view of your webcam.
- Click the "Scan QR Code" button.
- The captured image will be sent to the backend for processing.
Additional Notes
- Admin and Operator Access Codes:
- Use the code 1111 to access the operator interface.
- Use the code 2222 to access the admin interface.
- These can be adjusted in access.js if needed.
Python
: The main programming language used for implementing the server-side of the project.Flask
: A lightweight yet powerful web framework used to create and deploy web applications. Flask provides all the necessary tools and libraries for building server-side functionalities and is based on the principle of extensibility.OpenCV
: A computer vision library used for image processing. We use it for performing various image transformation operations that aid in improving QR code recognition, including noise filtering and distortion correction.pyzbar
: A specialized library for decoding QR codes. It provides accurate and fast reading of information from QR codes, which is critically important.scikit-learn
: One of the leading machine learning libraries used for versatile data processing. In our project, it is used to analyze text using the TF-IDF (Term Frequency-Inverse Document Frequency) algorithm, which allows efficient analysis and classification of text data.numpy
: A high-performance library for numerical computations that works with multi-dimensional arrays and matrices. It provides numerous mathematical functions, making it indispensable for data processing and performing complex calculations.
HTML
: A markup language used to create the structure of the web page. With it, you can define various elements of the page such as headings, paragraphs, forms, and buttons.CSS
: A stylesheet language used to style HTML elements. You can set the color, fonts, sizes, paddings, and other visual characteristics of web page elements.JavaScript
: A programming language used to add interactivity to the web page. In this project, it is necessary for managing interactions with the operator, such as capturing an image from the camera and sending it to the server.
Poetry
: A tool for dependency management and creating isolated virtual environments in Python. Poetry simplifies the installation and updating of packages, as well as managing versions, ensuring consistency and reproducibility of environments.pyright
: A fast and powerful static type analyzer for Python that helps identify type errors before the code execution, thereby increasing the reliability and quality of the software.ruff
: A linter designed to improve code quality and maintain the style. Ruff helps identify and fix stylistic errors, ensuring consistency and code cleanliness according to the set standards.
Gunicorn
: A high-performance WSGI HTTP server for running Flask applications in a production environment. Gunicorn provides scalability and reliability for your web application, allowing it to handle a large number of simultaneous requests and ensuring stable service operation.
/app
├── .replit
├── static
│ ├── script.js
│ └── styles.css
├── main.py
├── pyproject.toml
├── templates
│ └── index.html
├── ...
├── replit.nix
├── models.py
This project structure organizes code and resources logically, simplifying development and maintenance of the application.
main.py
: The main backend file containing Flask routes and logic for image and QR code processing.templates/index.html
: An HTML template for the main page of the application.pyproject.toml
: A configuration file for managing project dependencies and code linting settings (Pyright and Ruff).
- OpenCV (Open Source Computer Vision Library) — is used for performing various tasks related to image processing and QR code recognition. OpenCV is a powerful tool for computer vision and image processing, providing a wide range of functions and modules, including filtering, shape transformation, object recognition, and more. With its extensive capabilities, OpenCV enables efficient image processing to improve the quality of scanning and accuracy of QR code recognition.
- When the page loads, a script is initiated that requests access to the user's webcam:
navigator.mediaDevices.getUserMedia({ video: { width: 1280, height: 720 } })
.then(stream => {
video.srcObject = stream;
})
.catch(err => {
console.error("Ошибка доступа к камере: ", err);
});
-
The video stream from the webcam is displayed inside a
<video>
element, allowing the user to check the correct angle and position of the QR code before scanning. This element is placed in the center of the page for user convenience. -
The operator clicks the "Scan QR Code" button. This action captures the current image from the webcam and draws it onto a
<canvas>
element.
captureBtn.addEventListener('click', () => {
setTimeout(() => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.style.display = 'block';
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
- After drawing the image onto the
<canvas>
element, it is converted toBlob format
and sent to the server endpoint/scan-qr/
using theFetch API
:
canvas.toBlob((blob) => {
const formData = new FormData();
formData.append('file', blob, 'capture.png');
fetch('/scan-qr/', {
method: 'POST',
body: formData
})
- On the server, Flask processes this request at the
/scan-qr/
endpoint. The image is first read and converted into an object using Pillow (PIL):
file = request.files['file']
contents = file.read()
image = Image.open(io.BytesIO(contents))
image_np = np.array(image)
- The server performs several preprocessing steps on the image to improve the quality for reading QR codes. Preprocessing is done using a function called
preprocess_image
in multiple attempts:
attempts = 12
decoded_objects = []
for attempt in range(attempts):
processed_image = preprocess_image(image_np, attempt)
decoded_objects = decode(Image.fromarray(processed_image))
if decoded_objects:
break
- The library
pyzbar
is used to recognize and decode QR codes from preprocessed images:
if decoded_objects:
qr_data_list = []
image_draw = ImageDraw.Draw(image)
for obj in decoded_objects:
qr_data = obj.data.decode('utf-8')
qr_data_list.append(qr_data)
- The server creates markers on the original image to show the location of the QR codes using
OpenCV
:
points = obj.polygon
if len(points) == 4:
pts = np.array(points, dtype=np.int32)
cv2.polylines(image_np, [pts], isClosed=True, color=(0, 255, 0), thickness=2)
text_position = (points[0].x, points[0].y - 10)
image_draw.text(text_position, f"QR", fill=(255, 0, 0))
- An
alert
is displayed on the client side with the QR code scanning results:
.then((data) => {
alert('Данные QR-кода: ' + data.data);
canvas.style.display = 'none';
})
.catch(error => {
console.error('Ошибка:', error);
canvas.style.display = 'none';
});