Skip to content

SpectateurLinlan/OVDR

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

33 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ§₯ OVDR: Online Virtual Dressing Room

Project ID: [P2024‑16]
Project Title: Online Virtual Dressing Room with Advanced Try‑On and Clothing Retrieval Features
Team Name: TEAM2024.07
Supervisor: Dr. Qian Zhang

1. Project Overview

OVDR (Online Virtual Dressing Room) is a full-stack web application that enables users to virtually try on clothing using advanced computer vision and deep learning techniques. It supports personalized outfit recommendation, description-based search (powered by CLIP), and photorealistic try-on (using StableVITON).

A structured clothing dataset categorized into tops, bottoms, and dresses has also been developed, with each item annotated using descriptive captions. This dataset lays a solid foundation for future integration of semantic search and recommendation systems to enhance accuracy, as well as prompt-based try-on experiences.


2. Tasks & Deliverables

  • A web‑based application with an intuitive user interface.
  • A clothing dataset with text captions
  • StableVITON virtual try-on integration
  • CLIP-based text search system
  • User closet, combination and history tracking
  • RESTful API endpoints and full documentation
  • Efficient browsing and recommendation system integration

3. Installation Manual

Prerequisites

⚠️ The following tools are optional or will be installed later in the guide:

  • MySQL (Optional – Only required if you plan to deploy the database locally. See Step 5)
  • Visual C++ Build Tools (Required during Detectron2 setup. See Step 3) From VS Installer, choose Visual Studio Build Tool 2019, click "modify" and download the newest MSVC in single component and Desktop Development using C++ in desktop and mobile applications.

1 - Clone the Repository

git clone https://csprojects.nottingham.edu.cn/grp-team07-gitlab/grp-team07-gitlab-work.git
cd grp-team07-gitlab-work

2 - Set Up Backend Environment

Each time you run the program, "conda activate OVDR" is required

conda create -n OVDR python=3.10 -y
conda activate OVDR
pip install -r requirements.txt

conda create -n StableViton python=3.10 -y
conda activate StableVITON
pip install -r requirements.txt
pip install transformers==4.33.0
pip install huggingface-hub==0.24.6

3 - Prepare AI Models (StableVITON + CLIP)

conda activate StableVITON
cd backend
mkdir models
cd models

# Install Triton (for Windows)
git clone https://github.com/PrashantSaikia/Triton-for-Windows
cd Triton-for-Windows
pip install triton-2.0.0-cp310-cp310-win_amd64.whl
cd ..

# Download clip-vit-large-patch14
git clone https://huggingface.co/openai/clip-vit-large-patch14

# Download StableVITON (ensure Git LFS is installed)
git lfs install
git clone https://huggingface.co/spaces/rlawjdghek/StableVITON

# Download StavleVITON models
go to https://huggingface.co/spaces/rlawjdghek/StableVITON/tree/main
to download the `checkpoints dir` alone
https://huggingface.co/spaces/rlawjdghek/StableVITON/tree/main
download the checkpoints dir alone

Detectron2 for DensePose

To install detectron2 and DensePose on Windows, make sure Visual Studio Build Tools are installed:

  1. Download: Visual C++ Build Tools
  2. In the installer:
    • Select Visual Studio Build Tools 2019
    • Go to Modify, check:
      • βœ… MSVC (latest version, under β€œSingle Component”)
      • βœ… Desktop development with C++ workload
  3. Install and restart your terminal.

Now install detectron2 and DensePose:

πŸ’‘ Important: Use x64 Native Tools Command Prompt for VS 2019, not regular cmd or PowerShell

# Clone detectron2 repository
git clone https://github.com/facebookresearch/detectron2.git

# Activate your environment
conda activate StableViton

# Navigate to Detectron2 repo
cd your_store_project_path/backend/models/detectron2/

# Install detectron2
set DISTUTILS_USE_SDK=1 && pip install .

# Install DensePose
cd ./projects/DensePose
set DISTUTILS_USE_SDK=1 && pip install .

4 - Set Up Frontend

cd frontend
npm install
npm install concurrently wait-on --save-dev   # Install parallel running dependencies (if not installed)

5 - Set Up MySQL (Optional for Local Try-On Only)

CREATE DATABASE ovdr CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
mysql -u root -p ovdr < backend/database/ovdr_structure.sql
mysql -u root -p ovdr < backend/database/ovdr_data_only.sql

Configure your .env file:

USER_NAME=root
PASSWORD=yourpassword
HOSTNAME=127.0.0.1
PORT=3306
DATABASE=ovdr

For more information about shared team databases and access IPs, please refer to the Database Notes.

6 - revise the app.py (in StableVITON models)

from preprocess.detectron2.projects.DensePose.apply_net_gradio import DensePose4Gradio
from preprocess.humanparsing.run_parsing import Parsing
from preprocess.openpose.run_openpose import OpenPose

import os
import sys
import time
from glob import glob
from os.path import join as opj
from pathlib import Path

import gradio as gr
import torch
from omegaconf import OmegaConf
from PIL import Image
import spaces
print(torch.cuda.is_available(), torch.cuda.device_count())


from cldm.model import create_model
from cldm.plms_hacked import PLMSSampler
from utils_stableviton import get_mask_location, get_batch, tensor2img, center_crop

PROJECT_ROOT = Path(__file__).absolute().parents[1].absolute()
sys.path.insert(0, str(PROJECT_ROOT)) 

IMG_H = 1024
IMG_W = 768

openpose_model_hd = OpenPose(0)
openpose_model_hd.preprocessor.body_estimation.model.to('cuda')
parsing_model_hd = Parsing(0)
densepose_model_hd = DensePose4Gradio(
    cfg='preprocess/detectron2/projects/DensePose/configs/densepose_rcnn_R_50_FPN_s1x.yaml',
    model='https://dl.fbaipublicfiles.com/densepose/densepose_rcnn_R_50_FPN_s1x/165712039/model_final_162be9.pkl',
)

category_dict = ['upperbody', 'lowerbody', 'dress']
category_dict_utils = ['upper_body', 'lower_body', 'dresses']

#####model init >>>>
config = OmegaConf.load("./configs/VITON.yaml")
config.model.params.img_H = IMG_H
config.model.params.img_W = IMG_W
params = config.model.params

model = create_model(config_path=None, config=config)
model.load_state_dict(torch.load("./checkpoints/eternal_1024.ckpt", map_location="cpu")["state_dict"])
model = model.cuda()
model.eval()
sampler = PLMSSampler(model)

model2 = create_model(config_path=None, config=config)
model2.load_state_dict(torch.load("./checkpoints/VITONHD_1024.ckpt", map_location="cpu")["state_dict"])
model2 = model.cuda()
model2.eval()
sampler2 = PLMSSampler(model2)
#####model init <<<<

@spaces.GPU
@torch.autocast("cuda")
@torch.no_grad()
def stable_viton_model_hd(
        batch,
        n_steps,
):
    z, cond = model.get_input(batch, params.first_stage_key)
    z = z
    bs = z.shape[0]
    c_crossattn = cond["c_crossattn"][0][:bs]
    if c_crossattn.ndim == 4:
        c_crossattn = model.get_learned_conditioning(c_crossattn)
        cond["c_crossattn"] = [c_crossattn]
    uc_cross = model.get_unconditional_conditioning(bs)
    uc_full = {"c_concat": cond["c_concat"], "c_crossattn": [uc_cross]}
    uc_full["first_stage_cond"] = cond["first_stage_cond"]
    for k, v in batch.items():
        if isinstance(v, torch.Tensor):
            batch[k] = v.cuda()
    sampler.model.batch = batch

    ts = torch.full((1,), 999, device=z.device, dtype=torch.long)
    start_code = model.q_sample(z, ts)
    torch.cuda.empty_cache()
    output, _, _ = sampler.sample(
        n_steps,
        bs,
        (4, IMG_H//8, IMG_W//8),
        cond,
        x_T=start_code, 
        verbose=False,
        eta=0.0,
        unconditional_conditioning=uc_full,       
    )

    output = model.decode_first_stage(output)
    output = tensor2img(output)
    pil_output = Image.fromarray(output)
    return pil_output

@spaces.GPU
@torch.autocast("cuda")
@torch.no_grad()
def stable_viton_model_hd2(
        batch,
        n_steps,
):
    z, cond = model2.get_input(batch, params.first_stage_key)
    z = z
    bs = z.shape[0]
    c_crossattn = cond["c_crossattn"][0][:bs]
    if c_crossattn.ndim == 4:
        c_crossattn = model2.get_learned_conditioning(c_crossattn)
        cond["c_crossattn"] = [c_crossattn]
    uc_cross = model2.get_unconditional_conditioning(bs)
    uc_full = {"c_concat": cond["c_concat"], "c_crossattn": [uc_cross]}
    uc_full["first_stage_cond"] = cond["first_stage_cond"]
    for k, v in batch.items():
        if isinstance(v, torch.Tensor):
            batch[k] = v.cuda()
    sampler2.model.batch = batch

    ts = torch.full((1,), 999, device=z.device, dtype=torch.long)
    start_code = model2.q_sample(z, ts)
    torch.cuda.empty_cache()
    output, _, _ = sampler2.sample(
        n_steps, 
        bs,
        (4, IMG_H//8, IMG_W//8),
        cond,
        x_T=start_code, 
        verbose=False,
        eta=0.0,
        unconditional_conditioning=uc_full,       
    )

    output = model2.decode_first_stage(output)
    output = tensor2img(output)
    pil_output = Image.fromarray(output)
    return pil_output
    
@spaces.GPU
@torch.no_grad()
def process_hd(vton_img, garm_img, category_name, n_steps, is_custom):
    model_type = 'hd'
    # 0:upperbody; 1:lowerbody; 2:dress
    
    if category_name == 'tops':    category = 0
    elif category_name == 'bottoms':  category = 1
    elif category_name == 'dresses':     category = 2
    else:                               category = 0
    stt = time.time()
    print('load images... ', end='')
    # garm_img = Image.open(garm_img).resize((IMG_W, IMG_H))
    # vton_img = Image.open(vton_img).resize((IMG_W, IMG_H))
    garm_img = Image.open(garm_img).convert('RGB')
    vton_img = Image.open(vton_img).convert('RGB')
    
    vton_img = center_crop(vton_img)
    garm_img = garm_img.resize((IMG_W, IMG_H))
    vton_img = vton_img.resize((IMG_W, IMG_H))

    print('%.2fs' % (time.time() - stt))

    stt = time.time()
    print('get agnostic map... ', end='')
    keypoints = openpose_model_hd(vton_img.resize((IMG_W, IMG_H)))
    model_parse, _ = parsing_model_hd(vton_img.resize((IMG_W, IMG_H)))
    mask, mask_gray = get_mask_location(model_type, category_dict_utils[category], model_parse, keypoints, radius=5)
    mask = mask.resize((IMG_W, IMG_H), Image.NEAREST)
    mask_gray = mask_gray.resize((IMG_W, IMG_H), Image.NEAREST)
    masked_vton_img = Image.composite(mask_gray, vton_img, mask)  # agnostic map
    print('%.2fs' % (time.time() - stt))

    stt = time.time()
    print('get densepose... ', end='')
    vton_img = vton_img.resize((IMG_W, IMG_H))  # size for densepose
    densepose = densepose_model_hd.execute(vton_img)  # densepose
    print('%.2fs' % (time.time() - stt))

    batch = get_batch(
        vton_img, 
        garm_img, 
        densepose, 
        masked_vton_img, 
        mask, 
        IMG_H, 
        IMG_W
    )
    
    if is_custom:
        sample = stable_viton_model_hd(
            batch,
            n_steps,
        )
    else:
        sample = stable_viton_model_hd2(
            batch,
            n_steps,
        )
    return sample

def save_output_image(image):
    output_dir = "./output_images"
    os.makedirs(output_dir, exist_ok=True)

    filename = f"{time.time():.0f}.jpg"
    save_path = os.path.join(output_dir, filename)
    
    image.save(save_path)
    return os.path.abspath(save_path)

args = sys.argv[1:]
image_gene = process_hd(args[0],args[1],args[2],20,False)
out_path = save_output_image(image_gene)
print(out_path)
sys.exit(0)

7 - Run the Application (Ensure you are in ./frontend/)

conda activate OVDR
npm run dev

If you encounter the error:

[0] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.  
[0] - options.allowedHosts[0] should be a non-empty string.

Solution: Please modify the /frontend/node_modules/react-scripts/config/webpackDevServer.config.js file and change the allowedHosts configuration on line 46 to:

allowedHosts: "all",

7. Troubleshooting

1 - Error: ModuleNotFoundError

pip install -r requirements.txt again

2 - Error: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE

If you see an error like:

RROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. torch==2.0.1+cu117 from https://download.pytorch.org/... Expected sha256 ... Got ...

This means the downloaded PyTorch package has a different hash than the one recorded in requirements.txt. This is usually due to PyTorch officially updating the .whl file metadata.

βœ… Solution 1 – Manually download and install the correct PyTorch wheels:

  1. Visit: https://download.pytorch.org/whl/cu117
  2. Download the matching .whl files for your Python version (e.g. cp310 for Python 3.10):
    • torch-2.0.1+cu117-cp310-cp310-win_amd64.whl
    • torchvision-0.15.2+cu117-cp310-cp310-win_amd64.whl
    • torchaudio-2.0.2-cp310-cp310-win_amd64.whl
  3. Run:
pip install torch-*.whl torchvision-*.whl torchaudio-*.whl

The backend runs at http://localhost:5000, and the frontend at http://localhost:3000.


4. Project Structure

Organized by backend, frontend, image data, and documentation.


πŸ“ OVDR/ (Root Project)
OVDR/
β”œβ”€β”€ app.py                          # Project root entrypoint (if needed)
β”œβ”€β”€ README.md                       # Project overview
β”œβ”€β”€ .gitignore                      # Git ignored files

πŸ“ ./backend/ β€” Flask backend
β”œβ”€β”€ backend/                        # Flask backend
β”‚   β”œβ”€β”€ __init__.py                 # create_app() and app initialization
β”‚   β”œβ”€β”€ config.py                   # Config class for DB, mail, etc.
β”‚   β”œβ”€β”€ exts.py                     # db/mail/cors plugin initialization
β”‚   β”œβ”€β”€ .env                        # Environment variables for secrets
β”‚
β”‚   β”œβ”€β”€ database/                   # DB schema, data and documentation
β”‚   β”‚   β”œβ”€β”€ OVDR.sql
β”‚   β”‚   β”œβ”€β”€ ovdr_structure.sql
β”‚   β”‚   β”œβ”€β”€ ovdr_data_only.sql
β”‚   β”‚   β”œβ”€β”€ backup.sql
β”‚   β”‚   β”œβ”€β”€ ERD.png                 # Database Entity-Relationship Diagram
β”‚   β”‚   └── database.md             # DB documentation
β”‚
β”‚   β”œβ”€β”€ migrations/                 # Flask-Migrate migration files
β”‚
β”‚   β”œβ”€β”€ models/                     # Model directories
β”‚   β”‚   β”œβ”€β”€ clip-vit-large-patch14  # CLIP model
β”‚   β”‚   └── StableVITON/            # StableVITON try-on model
β”‚
β”‚   β”œβ”€β”€ routes/                     # Flask route blueprints
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ auth.py                 # Login/Register routes
β”‚   β”‚   β”œβ”€β”€ closet.py               # Clothing listing & closet management
β”‚   β”‚   β”œβ”€β”€ combination.py          # Outfit combination logic
β”‚   β”‚   β”œβ”€β”€ email.py                # Email sending routes
β”‚   β”‚   β”œβ”€β”€ forms.py                # WTForms for validation
β”‚   β”‚   β”œβ”€β”€ history.py              # Browsing history
β”‚   β”‚   β”œβ”€β”€ process.py              # Try-on image generation
β”‚   β”‚   β”œβ”€β”€ recommend.py            # Recommendation system
β”‚   β”‚   β”œβ”€β”€ search.py               # CLIP-based text search
β”‚   β”‚   └── user_image.py           # User image upload & fetch
β”‚
β”‚   β”œβ”€β”€ scripts/                    # One-time utility scripts
β”‚   β”‚   β”œβ”€β”€ image_embedding.py
β”‚   β”‚   β”œβ”€β”€ insert_clothes_data.py
β”‚   β”‚   β”œβ”€β”€ precompute_similarity.py
β”‚   β”‚   β”œβ”€β”€ qwen_generate_caption.py
β”‚   β”‚   β”œβ”€β”€ recommend_clicktime.py
β”‚   β”‚   β”œβ”€β”€ recommend_sim_algorithm.py
β”‚   β”‚   β”œβ”€β”€ rename_clothes.py
β”‚   β”‚   β”œβ”€β”€ save_CLIP_model.py
β”‚   β”‚   β”œβ”€β”€ search_algorithm.py
β”‚   β”‚   β”œβ”€β”€ search_api.py
β”‚   β”‚   └── similarity_matrix.npy
β”‚
β”‚   β”œβ”€β”€ utils/                      # Utility modules
β”‚   β”‚   β”œβ”€β”€ caption_utils.py        # Caption formatting and generation
β”‚   β”‚   β”œβ”€β”€ download_utils.py       # Download cloth image from URL
β”‚   β”‚   β”œβ”€β”€ helpers.py              # URL/path formatting utilities
β”‚   β”‚   β”œβ”€β”€ image_utils.py          # Save/rename/delete user images
β”‚   β”‚   β”œβ”€β”€ stableviton_runner.py   # Run StableVITON subprocess
β”‚   β”‚   β”œβ”€β”€ static_serve.py         # Static image serving utilities
β”‚   β”‚   β”œβ”€β”€ config.py               # Duplicate? (backend/config.py used)
β”‚   β”‚   β”œβ”€β”€ exts.py                 # Duplicate? (used for plugin setup)
β”‚   β”‚   └── models.py               # SQLAlchemy models (User, Clothing...)
β”‚
β”‚   └── similarity_matrix.npy       # Precomputed similarity matrix

πŸ“ ./data/ β€” Static & dynamic image data
β”œβ”€β”€ data/                           # Image assets & user uploads
β”‚   β”œβ”€β”€ clothes/                    # Main clothing image dataset
β”‚   β”‚   β”œβ”€β”€ tops/
β”‚   β”‚   β”‚   β”œβ”€β”€ cloth/
β”‚   β”‚   β”‚   β”‚    └── 000001_top.jpg
β”‚   β”‚   β”‚   β”œβ”€β”€ cloth-mask/
β”‚   β”‚   β”‚   └── model-tryon/
β”‚   β”‚   β”œβ”€β”€ bottoms/
β”‚   β”‚   β”œβ”€β”€ dresses/
β”‚   β”‚   └── captions/               # Generated captions JSONs
β”‚
β”‚   β”œβ”€β”€ users/
β”‚   β”‚   β”œβ”€β”€ image/                  # Uploaded user full-body images
β”‚   β”‚     └── 1.jpg                 # Named by user_id
β”‚
β”‚   └── combinations/               # Output try-on images
β”‚       └── user_1/
β”‚           └── 000001.jpg

πŸ“ ./frontend/ β€” React-based frontend
β”œβ”€β”€ frontend/                       # React frontend
β”‚   β”œβ”€β”€ node_modules/               # Frontend dependencies
β”‚   β”œβ”€β”€ public/
β”‚   β”œβ”€β”€ src/                        # Main frontend code
β”‚   β”‚   β”œβ”€β”€ App.js / App.css
β”‚   β”‚   β”œβ”€β”€ ClothesDetail.js / .css
β”‚   β”‚   β”œβ”€β”€ FullCloset.js / .css
β”‚   β”‚   β”œβ”€β”€ History.js / .css
β”‚   β”‚   β”œβ”€β”€ Home.js / .css
β”‚   β”‚   β”œβ”€β”€ Login.js / .css
β”‚   β”‚   β”œβ”€β”€ Register.js
β”‚   β”‚   β”œβ”€β”€ SendImage.js / .css
β”‚   β”‚   β”œβ”€β”€ TryOn.js / .css
β”‚   β”‚   β”œβ”€β”€ UploadImage.js / .css
β”‚   β”‚   β”œβ”€β”€ index.js / index.css
β”‚   β”‚   └── setupTests.js / reportWebVitals.js
β”‚   β”œβ”€β”€ package.json                # React project config
β”‚   β”œβ”€β”€ package-lock.json
β”‚   └── README.md                   # Frontend description

πŸ“ ./docs/ β€” Project documentation
β”œβ”€β”€ docs/                           # Project documentation and static info website
β”‚   β”œβ”€β”€ JSdocs/
β”‚   β”œβ”€β”€ code_report.md              # Final report with structure & logic
β”‚   β”œβ”€β”€ api_documentation.md        # Full REST API documentation
β”‚   β”œβ”€β”€ installation_manual.html
β”‚   β”œβ”€β”€ user_manual.pdf
β”‚   β”œβ”€β”€ Summary_of_quality_assurance.pdf  # Quality testing doc
β”‚   β”œβ”€β”€ css/
β”‚   β”œβ”€β”€ minutes/
β”‚   β”œβ”€β”€ src/
β”‚   └── index.html           # Presentation site

5. Documentation

Name Description
User Manual Instructions for using the frontend interface
Jsdocs Detailed technical documentation for all functions
requirements.txt Python dependency list for backend environment setup
Code Report Architecture, logic explanations, and code structure overview
API Documentation Full RESTful API documentation for backend modules
Summary of Quality Assurance Final QA report and testing results

6. Database Setup & Notes

This project uses a MySQL-compatible database running on a designated local server, typically hosted on the developer machine for team access and testing.

Common Database IPs

The following IP addresses are commonly used to access the database:

  • 10.176.45.0
  • 172.19.108.9

These IPs refer to the developer machine that runs the MySQL server.
If you are unsure about database access or need permissions, please contact Zixin Ding (ssyzd4@nottingham.edu.cn).


Local Testing (Try-On Demo / Offline Setup)

If you only want to test the virtual try-on feature locally, without syncing to the main team database, you can migrate the schema and data to your own machine.

MySQL Setup (Local):

  1. Install MySQL:
    Official download: https://www.mysql.com/cn/downloads/

  2. Create a new database:

    CREATE DATABASE ovdr CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  3. Import the table structure and data:

    mysql -u root -p ovdr < backend/database/ovdr_structure.sql
    mysql -u root -p ovdr < backend/database/ovdr_data_only.sql
  4. Edit .env file located in ./backend/ with your local config:

    USER_NAME=root
    PASSWORD=yourpassword
    HOSTNAME=127.0.0.1
    PORT=3306
    DATABASE=ovdr

This allows you to test try-on, closet, history, and search functions independently, without connecting to the shared database.


7. Team Members & Contact

This project was completed by TEAM2024.07 as part of the [P2024‑16] Online Virtual Dressing Room capstone.

Name Role & Responsibilities Contact
Zhihao Cao group leader,StableVITON try-on module, combination saving, bug fixing, Installation Manual, Final Report scyzc10@nottingham.edu.cn
Zixin Ding Backend architecture, dataset and database, caption generation, user auth, upload, closet and history logic, frontend improvement, bug fixing, Code Report, README, Installation Manual, Final Report ssyzd4@nottingham.edu.cn
Peini She React frontend development, combination and email routing, bug fixing, User Manual writing scyps2@nottingham.edu.cn
Jinghao Liu &
Zihan Zhou
Search and Recommendation module with CLIP, embedding logic, semantic search, Quality Assurance scyjl16@nottingham.edu.cn
scyzz15@nottingham.edu.cn

This project was developed by Team202407 as part of the COMP2043 Software Engineering Group Project at the University of Nottingham, Ningbo, China.

About

Online Virtual Dressing Room

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 38.4%
  • HTML 33.9%
  • JavaScript 17.9%
  • CSS 9.7%
  • Mako 0.1%