Python Forum

Full Version: Management software with image comparison
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi, let me start by saying I'm a beginner.
I wanted to try my hand at this adventure, convinced that with ChatGPT 4 I would be able to do it.
But here I am.

I need to create a management software that can be managed from a browser.
Management software to be implemented on a Raspberry PI 5 with OS having Raspberry PI OS installed as the operating system.

Purpose of the management system:
Compare 2 images and if they are similar for a percentage equal to or greater than that required by the project, the project is approved, otherwise you are asked to insert a new image.

Management software structure:

Management name: Antonio's Quality Control QC System


Home page: with two buttons Registration (Registration Page) and Login (Login Page)

Registration page:
- Username
- First name
- Surname
- City
- Email address
- Password
- Mobile phone
As soon as the account is created, there must be 2 fields left blank in the user database:
- Reference code (4 digits)
- User Type: which can be Operator or Administrator.
These last two fields will be set via the User Page

The management software must immediately have an Administrator user, with:
- Username: antonio
- Name: Antonio
- Password: password123
- City: City
- Surname: Surname
- Email address: test@test.com
- User Type: Administrator
- Reference code: 0000

Login page: allows access via username and password. Depending on the type of user, it opens the Operator Dashboard Page or the Administrator Dashboard Page

Create Project page:
- Project name
- Place
- Project description
- Project Code
- Reference Code
- Example photo (to be uploaded via upload)
- Compatibility Percentage Required (value from 0 to 100)
- Project status (default "to be worked")
- Comparison photo: blank until compared

View Projects page: contains the list of projects with the status indicated as "Worked" or "To Be Worked". Allows you to select whether to display Worked or To Be Worked projects.

Project page:
- View the single project
- Allows you to load the image to compare with the one present in the project.
- Once loaded, it allows you to start the comparison
- If the image comparison does not exceed the Required Compatibility Percentage value, a message is returned to proceed with the new upload and the project status remains in To Be Worked
- If the image comparison exceeds the Required Compatibility Percentage value, the image is saved and displayed in the project. The project status changes to Worked

User Page: Allows you to edit and save the user card. It then displays the data entered when you registered and allows you to set the Reference Code and the User Type field with a save changes button to save them.

Users Page: displays all registered users and allows you to click on the user to open the User Page

Operator Dashboard Page:
- Automatically opened after login of the user who does not have a value in the User Type field or whose value is Operator
- Displays the Project to Work button which contains the projects that have the Reference Code equal to your account and are listed as Project To Work Status.
- Displays the Worked Project button which contains the projects that have the Reference Code equal to your account and appear as Worked Project Status
- For each project displayed in the list there must be a button to open the corresponding Project Page.

Administrator Dashboard Page:
- Automatically opened for those who log in as administrator (by default user antonio password password123) or have an account with Administrator User Type set
- Button to access the Users Page
- Button to access the Create Project page
- Button to access the Project View Page

This is the app.py code I was able to create via chatgpt4

Could you help me understand how to actually implement the project?


----------------------------------------

from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email
from flask_login import LoginManager, UserMixin, login_user, login_required
from werkzeug.utils import secure_filename
from flask_bcrypt import Bcrypt
import os
import cv2
import numpy as np
from skimage.metrics import structural_similarity as ssim

app = Flask(__name__)


app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///antoniosqc.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'password123'
app.config['UPLOAD_FOLDER'] = '/home/pi/AntoniosQCSystem/uploaded_images'

db = SQLAlchemy(app)
bcrypt = Bcrypt(app)

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

class LoginForm(FlaskForm):
    username = StringField('Nome Utente', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    submit = SubmitField('Accedi')

class RegistrationForm(FlaskForm):
    username = StringField('Nome Utente', validators=[DataRequired()])
    firstname = StringField('Nome', validators=[DataRequired()])
    lastname = StringField('Cognome', validators=[DataRequired()])
    city = StringField('Città', validators=[DataRequired()])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    phone = StringField('Cellulare', validators=[DataRequired()])
    submit = SubmitField('Registra')

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    first_name = db.Column(db.String(80), nullable=False)
    last_name = db.Column(db.String(80), nullable=False)
    city = db.Column(db.String(80), nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)
    phone = db.Column(db.String(20), nullable=False)
    reference_code = db.Column(db.String(4), nullable=True)
    user_type = db.Column(db.String(10), nullable=True)

class Project(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    location = db.Column(db.String(100), nullable=False)
    description = db.Column(db.String(500), nullable=False)
    project_code = db.Column(db.String(20), nullable=False)
    reference_code = db.Column(db.String(4), nullable=False)
    sample_image = db.Column(db.String(100), nullable=True)
    required_match_percentage = db.Column(db.Integer, nullable=False)
    status = db.Column(db.String(20), default='da lavorare')
    comparative_image = db.Column(db.String(100), nullable=True)
def create_app():
    with app.app_context():
        db.create_all()
    return app

if __name__ == '__main__':
    create_app().run(debug=True, host='0.0.0.0')
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/')
def home():
    return render_template('home.html')


@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user and bcrypt.check_password_hash(user.password, form.password.data):
            login_user(user)
            return redirect(url_for('dashboard'))
        return '<h1>Invalid username or password</h1>'
    return render_template('login.html', form=form)

@app.route('/registration', methods=['GET', 'POST'])
def registration():
    form = RegistrationForm()
    if form.validate_on_submit():
        hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
        new_user = User(username=form.username.data, firstname=form.firstname.data,
                        lastname=form.lastname.data, city=form.city.data,
                        email=form.email.data, password=hashed_password,
                        phone=form.phone.data)
        db.session.add(new_user)
        db.session.commit()
        return redirect(url_for('login'))
    return render_template('registration.html', form=form)

@app.route('/dashboard')
@login_required
def dashboard():
    return render_template('dashboard_admin.html' if current_user.user_type == 'Amministratore' else 'dashboard_operator.html', projects=Project.query.filter_by(reference_code=current_user.reference_code).all())

@app.route('/project/<int:project_id>', methods=['GET', 'POST'])
@login_required
def project_page(project_id):
    project = Project.query.get_or_404(project_id)
    if request.method == 'POST' and 'comparative_image' in request.files:
        file = request.files['comparative_image']
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file.save(file_path)
            project.comparative_image = file_path
            similarity = compare_images(project.sample_image, project.comparative_image)
            project.status = 'lavorato' if similarity >= (project.required_match_percentage / 100.0) else 'da lavorare'
            db.session.commit()
            return redirect(url_for('project_page', project_id=project_id))
    return render_template('project_page.html', project=project)

def compare_images(img_path1, img_path2):
    image1 = cv2.imread(img_path1, cv2.IMREAD_GRAYSCALE)
    image2 = cv2.imread(img_path2, cv2.IMREAD_GRAYSCALE)
    s, diff = ssim(image1, image2, full=True)
    return s

@app.route('/manage_users')
@login_required
def manage_users():
    return render_template('manage_users.html', users=User.query.all())

@app.route('/add_user', methods=['GET', 'POST'])
@login_required
def add_user():
    form = RegistrationForm()
    if form.validate_on_submit():
        hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
        new_user = User(username=form.username.data, firstname=form.firstname.data,
                        lastname=form.lastname.data, city=form.city.data,
                        email=form.email.data, password=hashed_password,
                        phone=form.phone.data, user_type='Operatore')
        db.session.add(new_user)
        db.session.commit()
        return redirect(url_for('manage_users'))
    return render_template('registration.html', form=form)

@app.route('/create_project', methods=['GET', 'POST'])
@login_required
def create_project():
    if request.method == 'POST':
        new_project = Project(
            name=request.form['name'],
            location=request.form['location'],
            description=request.form['description'],
            project_code=request.form['project_code'],
            reference_code=request.form['reference_code'],
            sample_image=request.form.get('sample_image'),  # optional
            required_match_percentage=int(request.form['required_match_percentage'])
        )
        db.session.add(new_project)
        db.session.commit()
        return redirect(url_for('dashboard'))
    return render_template('create_project.html')

@app.route('/update_user/<int:user_id>', methods=['POST'])
@login_required
def update_user(user_id):
    user = User.query.get_or_404(user_id)
    user.first_name = request.form['firstname']
    user.last_name = request.form['lastname']
    user.email = request.form['email']
    user.phone = request.form['phone']
    user.reference_code = request.form['reference_code']
    user.user_type = request.form['user_type']
    db.session.commit()
    return redirect(url_for('manage_users'))

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)
    db.create_all()