3/24/2025

Setup Online annotation with LabelMe

Complete Tutorial: LabelMe with Login System and Dataset Management

This guide provides step-by-step instructions for setting up LabelMe with a custom login system and proper dataset management. We'll cover the entire workflow: login → annotation → save → logout.

System Overview

We'll build a system with the following components:

  1. LabelMe running in a Docker container with a configured dataset folder
  2. PHP-based authentication system
  3. Web server (Apache) to host the login portal
  4. Dataset management structure

Prerequisites

  • A Linux server (Ubuntu 20.04 LTS or newer recommended)
  • Root or sudo access to the server
  • Docker and Docker Compose installed
  • Apache web server with PHP support

Part 1: Server Preparation

Step 1: Update System and Install Required Packages

# Update package lists
sudo apt update
sudo apt upgrade -y

# Install necessary packages
sudo apt install -y docker.io docker-compose apache2 php libapache2-mod-php php-json
sudo systemctl enable docker
sudo systemctl start docker

# Add your user to docker group to avoid using sudo with docker commands
sudo usermod -aG docker $USER
# Log out and log back in for this to take effect

Step 2: Create Project Directory Structure

# Create main project directory
mkdir -p ~/labelme-project
cd ~/labelme-project

# Create directories for different components
mkdir -p docker-labelme
mkdir -p web-portal
mkdir -p datasets/{project1,project2}
mkdir -p annotations

# Add some sample images to project1 (optional)
# You can replace this with your own dataset copying commands
mkdir -p datasets/project1/images
# Copy some sample images if you have them
# cp /path/to/your/images/*.jpg datasets/project1/images/

Part 2: Set Up LabelMe Docker Container

Step 1: Create Docker Compose Configuration

Create a file docker-labelme/docker-compose.yml:

cd ~/labelme-project/docker-labelme
nano docker-compose.yml

Add the following content:

version: '3'
services:
  labelme:
    image: wkentaro/labelme
    container_name: labelme-server
    ports:
      - "8080:8080"
    volumes:
      - ../datasets:/data
      - ../annotations:/home/developer/.labelmerc
    environment:
      - LABELME_SERVER=1
      - LABELME_PORT=8080
      - LABELME_HOST=0.0.0.0
    command: labelme --server --port 8080 --host 0.0.0.0 /data
    restart: unless-stopped

Step 2: Create LabelMe Configuration File

This step ensures annotations are saved in the proper format and location:

cd ~/labelme-project
nano annotations/.labelmerc

Add the following content:

{
  "auto_save": true,
  "display_label_popup": true,
  "store_data": true,
  "keep_prev": false,
  "flags": null,
  "flags_2": null,
  "flags_3": null,
  "label_flags": null,
  "labels": ["person", "car", "bicycle", "dog", "cat", "tree", "building"],
  "file_search": true,
  "show_label_text": true
}

Customize the labels list according to your annotation needs.

Step 3: Start LabelMe Container

cd ~/labelme-project/docker-labelme
docker-compose up -d

Verify it's running:

docker ps

You should see the labelme-server container running and listening on port 8080.

Part 3: Set Up Web Portal with Login System

Step 1: Create the Login Page

cd ~/labelme-project/web-portal
nano index.php

Add the following content:

<?php
// Display errors during development (remove in production)
ini_set('display_errors', 1);
error_reporting(E_ALL);

// Start session
session_start();

// Check if there's an error message
$error_message = isset($_SESSION['error_message']) ? $_SESSION['error_message'] : '';
// Clear error message after displaying it
unset($_SESSION['error_message']);
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LabelMe Login</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        .login-container {
            background-color: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            width: 350px;
        }
        h2 {
            text-align: center;
            color: #333;
            margin-bottom: 20px;
        }
        input[type="text"],
        input[type="password"] {
            width: 100%;
            padding: 12px;
            margin: 8px 0;
            display: inline-block;
            border: 1px solid #ccc;
            box-sizing: border-box;
            border-radius: 4px;
        }
        button {
            background-color: #4CAF50;
            color: white;
            padding: 14px 20px;
            margin: 10px 0;
            border: none;
            cursor: pointer;
            width: 100%;
            border-radius: 4px;
            font-size: 16px;
        }
        button:hover {
            opacity: 0.8;
        }
        .error-message {
            color: #f44336;
            text-align: center;
            margin-top: 10px;
        }
        .logo {
            text-align: center;
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <div class="login-container">
        <div class="logo">
            <h2>LabelMe Annotation</h2>
        </div>
        <form id="loginForm" action="auth.php" method="post">
            <div>
                <label for="username"><b>Username</b></label>
                <input type="text" placeholder="Enter Username" name="username" required>
            </div>
            <div>
                <label for="password"><b>Password</b></label>
                <input type="password" placeholder="Enter Password" name="password" required>
            </div>
            <div>
                <label for="project"><b>Select Project</b></label>
                <select name="project" style="width: 100%; padding: 12px; margin: 8px 0; display: inline-block; border: 1px solid #ccc; box-sizing: border-box; border-radius: 4px;">
                    <option value="project1">Project 1</option>
                    <option value="project2">Project 2</option>
                </select>
            </div>
            <button type="submit">Login</button>
            <?php if (!empty($error_message)): ?>
                <div class="error-message"><?php echo htmlspecialchars($error_message); ?></div>
            <?php endif; ?>
        </form>
    </div>
</body>
</html>

Step 2: Create the Authentication Script

cd ~/labelme-project/web-portal
nano auth.php

Add the following content:

<?php
// Start session management
session_start();

// Display errors during development (remove in production)
ini_set('display_errors', 1);
error_reporting(E_ALL);

// Configuration - Store these securely in production
$users = [
    'admin' => [
        'password' => password_hash('admin123', PASSWORD_DEFAULT), // Use hashed passwords
        'role' => 'admin'
    ],
    'user1' => [
        'password' => password_hash('user123', PASSWORD_DEFAULT),
        'role' => 'annotator'
    ],
    'user2' => [
        'password' => password_hash('user456', PASSWORD_DEFAULT),
        'role' => 'annotator'
    ]
];

// Base path to the LabelMe application
$labelme_base_url = 'http://localhost:8080'; // Change this to your LabelMe server address

// Handle login form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = isset($_POST['username']) ? $_POST['username'] : '';
    $password = isset($_POST['password']) ? $_POST['password'] : '';
    $project = isset($_POST['project']) ? $_POST['project'] : 'project1';
    
    // Validate credentials
    if (isset($users[$username]) && password_verify($password, $users[$username]['password'])) {
        // Set session variables
        $_SESSION['logged_in'] = true;
        $_SESSION['username'] = $username;
        $_SESSION['role'] = $users[$username]['role'];
        $_SESSION['project'] = $project;
        $_SESSION['last_activity'] = time();
        
        // Redirect to LabelMe
        header("Location: labelme.php");
        exit;
    } else {
        // Failed login
        $_SESSION['error_message'] = "Invalid username or password";
        header("Location: index.php");
        exit;
    }
}

// For logout
if (isset($_GET['logout'])) {
    // Log this logout
    $log_file = 'user_activity.log';
    $log_message = date('Y-m-d H:i:s') . " - User: " . ($_SESSION['username'] ?? 'unknown') . 
                " - Action: Logged out\n";
    file_put_contents($log_file, $log_message, FILE_APPEND);
    
    // Clear session data
    session_unset();
    session_destroy();
    
    // Redirect to login page
    header("Location: index.php");
    exit;
}
?>

Step 3: Create the LabelMe Proxy Page

cd ~/labelme-project/web-portal
nano labelme.php

Add the following content:

<?php
// Start session management
session_start();

// Display errors during development (remove in production)
ini_set('display_errors', 1);
error_reporting(E_ALL);

// Check if user is logged in
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
    // Not logged in, redirect to login page
    header("Location: index.php");
    exit;
}

// Security: Check for session timeout (30 minutes)
$timeout = 30 * 60; // 30 minutes in seconds
if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > $timeout)) {
    // Session has expired
    session_unset();
    session_destroy();
    header("Location: index.php?timeout=1");
    exit;
}

// Update last activity time
$_SESSION['last_activity'] = time();

// Configuration
$labelme_base_url = 'http://localhost:8080'; // Change this to your LabelMe server address
$project = $_SESSION['project'] ?? 'project1';
$labelme_url = $labelme_base_url . '/' . $project;

// Log user activity
$log_file = 'user_activity.log';
$log_message = date('Y-m-d H:i:s') . " - User: " . $_SESSION['username'] . 
               " - Role: " . $_SESSION['role'] . 
               " - Project: " . $project . 
               " - Action: Accessed LabelMe\n";
file_put_contents($log_file, $log_message, FILE_APPEND);
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LabelMe Annotation Tool</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
        }
        .header {
            background-color: #333;
            color: white;
            padding: 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .user-info {
            font-size: 14px;
        }
        .logout-btn {
            background-color: #f44336;
            color: white;
            border: none;
            padding: 5px 10px;
            cursor: pointer;
            border-radius: 3px;
            text-decoration: none;
            margin-left: 10px;
        }
        .logout-btn:hover {
            background-color: #d32f2f;
        }
        .project-selector {
            margin-left: 20px;
        }
        iframe {
            width: 100%;
            height: calc(100% - 50px);
            border: none;
        }
    </style>
</head>
<body>
    <div class="header">
        <div>
            <h3 style="margin:0;">LabelMe Annotation Tool</h3>
            <span>Project: <strong><?php echo htmlspecialchars($project); ?></strong></span>
        </div>
        <div class="user-info">
            Logged in as: <strong><?php echo htmlspecialchars($_SESSION['username']); ?></strong> 
            (<?php echo htmlspecialchars($_SESSION['role']); ?>)
            
            <form method="post" action="" style="display:inline-block">
                <select name="project" class="project-selector" onchange="this.form.submit()">
                    <option value="project1" <?php echo $project == 'project1' ? 'selected' : ''; ?>>Project 1</option>
                    <option value="project2" <?php echo $project == 'project2' ? 'selected' : ''; ?>>Project 2</option>
                </select>
            </form>
            
            <a href="auth.php?logout=1" class="logout-btn">Logout</a>
        </div>
    </div>
    
    <iframe src="<?php echo $labelme_url; ?>" allow="fullscreen"></iframe>
</body>
</html>

<?php
// Handle project switching
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['project'])) {
    $newProject = $_POST['project'];
    $_SESSION['project'] = $newProject;
    
    // Log project switch
    $log_message = date('Y-m-d H:i:s') . " - User: " . $_SESSION['username'] . 
                  " - Action: Switched to project " . $newProject . "\n";
    file_put_contents($log_file, $log_message, FILE_APPEND);
    
    // Redirect to refresh the page with new project
    header("Location: labelme.php");
    exit;
}
?>

Step 4: Setup Apache Virtual Host

sudo nano /etc/apache2/sites-available/labelme-portal.conf

Add the following configuration:

<VirtualHost *:80>
    ServerName labelme.yourdomain.com  # Change this to your domain or IP
    DocumentRoot /home/username/labelme-project/web-portal  # Update with your actual path
    
    <Directory /home/username/labelme-project/web-portal>  # Update with your actual path
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    ErrorLog ${APACHE_LOG_DIR}/labelme-error.log
    CustomLog ${APACHE_LOG_DIR}/labelme-access.log combined
</VirtualHost>

Update the paths to match your actual user and directory structure.

Step 5: Enable the Site and Restart Apache

sudo a2ensite labelme-portal.conf
sudo systemctl restart apache2

Step 6: Set Proper Permissions

# Set appropriate permissions for the web files
cd ~/labelme-project
sudo chown -R www-data:www-data web-portal
sudo chmod -R 755 web-portal

# Ensure the annotation directory is writable
sudo chown -R www-data:www-data annotations
sudo chmod -R 777 annotations

# Ensure datasets are accessible
sudo chmod -R 755 datasets

Part 4: Dataset Management

Step 1: Organize Your Datasets

Structure your dataset directories as follows:

datasets/
├── project1/
│   ├── images/
│   │   ├── image1.jpg
│   │   ├── image2.jpg
│   │   └── ...
│   └── annotations/  # LabelMe will save annotations here
├── project2/
│   ├── images/
│   │   ├── image1.jpg
│   │   └── ...
│   └── annotations/
└── ...

Step 2: Add Scripts for Managing Datasets (Optional)

Create a script to add new projects:

cd ~/labelme-project
nano add-project.sh

Add the following content:

#!/bin/bash
# Script to add a new project to the LabelMe setup

# Check if a project name was provided
if [ -z "$1" ]; then
    echo "Usage: $0 <project_name>"
    exit 1
fi

PROJECT_NAME="$1"
PROJECT_DIR="$HOME/labelme-project/datasets/$PROJECT_NAME"

# Create project directory structure
mkdir -p "$PROJECT_DIR/images"
mkdir -p "$PROJECT_DIR/annotations"

# Set permissions
chmod -R 755 "$PROJECT_DIR"

# Update the web portal to include the new project
# (This is a simplified approach - you'll need to manually edit index.php and labelme.php)
echo "Project directory created at: $PROJECT_DIR"
echo "Now copy your images to: $PROJECT_DIR/images/"
echo "Remember to manually update index.php and labelme.php to include the new project"

Make the script executable:

chmod +x add-project.sh

Part 5: Testing the Complete System

Step 1: Access the Web Portal

Open your browser and navigate to:

  • http://your-server-ip/ or http://labelme.yourdomain.com/

Step 2: Login and Test the Workflow

  1. Log in with the credentials (e.g., username: admin, password: admin123)
  2. Select a project from the dropdown
  3. After login, you should see the LabelMe interface embedded in the page
  4. Test annotating an image:
    • Click on an image
    • Draw polygons/shapes around objects
    • Enter labels for the objects
    • Annotations are auto-saved to the corresponding project folder
  5. Try switching projects using the dropdown in the header
  6. Log out and verify you're redirected to the login page

Part 6: Security Enhancements (for Production)

Enable HTTPS

sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d labelme.yourdomain.com

Improve Password Security

Edit the auth.php file to use a database instead of hardcoded users.

Troubleshooting

LabelMe Not Loading

If LabelMe doesn't load in the iframe:

  1. Check if LabelMe is running: docker ps
  2. Make sure port 8080 is accessible
  3. Check the Docker container logs: docker logs labelme-server

Permission Issues

If you encounter permission issues with annotations:

sudo chmod -R 777 ~/labelme-project/annotations
sudo chown -R www-data:www-data ~/labelme-project/datasets

Annotation not Saving

If annotations aren't saving properly:

  1. Check the .labelmerc configuration file
  2. Verify the permissions on the annotations directory
  3. Check for error messages in the Apache logs: sudo tail -f /var/log/apache2/error.log

Conclusion

You now have a complete LabelMe annotation system with:

  • Secure login/authentication
  • Project selection
  • Dataset organization
  • User activity logging
  • Session management

This setup allows your team to collaborate on annotation projects while maintaining control over who can access the system and what projects they can work on.

No comments:

Post a Comment