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.

save labelme json data

Save json and image for labelme


..

def make_labelme_json(list_ltrb, img, label, img_full_fn):

h, w, _ = img.shape
shape_dict =[]

for v in list_ltrb:
x1, y1, x2, y2 = v
adict={"label": label, "points":[[x1,y1],[x2,y2]], "group_id": None, "shape_type":"rectangle", "flags":{}}
shape_dict.append(adict)

image_string = cv2.imencode('.jpg', img)[1]
image_string = base64.b64encode(image_string).decode()
#make string image dict
wdict={"version":"4.5.6", "flags": {}, "shapes":shape_dict, "imagePath": img_full_fn, "imageData":image_string}

return wdict


def save_json_img(wdict, labelme_path, fn_only, img):
#save json
str_type = json.dumps(wdict) #dic to json
prefix_fn = "{}{}".format(labelme_path, fn_only)
f= open("{}.json".format(prefix_fn),"w+")
f.write(str_type)
f.close

#save image
cv2.imwrite("{}.jpg".format(prefix_fn), img)

wdict = make_labelme_json(list_ltrb, img,'lp', './'+fn )
save_json_img(wdict, labelme_path, fn_only, img)

..