shiue2000 commited on
Commit
f804ab9
·
verified ·
1 Parent(s): 70de40b

Upload 7 files

Browse files
Files changed (7) hide show
  1. Dockerfile +9 -0
  2. README.md +5 -5
  3. app.py +150 -0
  4. procfile +1 -0
  5. requirements.txt +6 -0
  6. templates/.DS_Store +0 -0
  7. templates/index.html +199 -0
Dockerfile ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ RUN pip install --upgrade pip
4
+ RUN pip install mercury==2.4.3
5
+
6
+ COPY . /code
7
+ WORKDIR /code
8
+
9
+ CMD ["mercury", "run", "app.py"]
README.md CHANGED
@@ -1,14 +1,14 @@
1
  ---
2
- title: Convert2Color Image
3
- emoji: 👁
4
- colorFrom: yellow
5
  colorTo: blue
6
  sdk: gradio
7
- sdk_version: 5.42.0
8
  app_file: app.py
9
  pinned: false
10
  license: cc
11
- short_description: Convert2Color_Image
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Magic_Image_BlackWhite_To_Color
3
+ emoji: 🌍
4
+ colorFrom: blue
5
  colorTo: blue
6
  sdk: gradio
7
+ sdk_version: 5.38.0
8
  app_file: app.py
9
  pinned: false
10
  license: cc
11
+ short_description: convert black and white to colored pictures
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2
3
+ import numpy as np
4
+ from flask import Flask, request, render_template, url_for
5
+ from werkzeug.utils import secure_filename
6
+
7
+ app = Flask(__name__, static_folder='static')
8
+
9
+ # --- Directory Setup ---
10
+ BASE_DIR = os.path.abspath(os.path.dirname(__file__))
11
+ STATIC_FOLDER = os.path.join(BASE_DIR, 'static')
12
+ UPLOAD_FOLDER = os.path.join(STATIC_FOLDER, 'uploads')
13
+ OUTPUT_FOLDER = os.path.join(STATIC_FOLDER, 'outputs')
14
+ MODEL_FOLDER = os.path.join(BASE_DIR, 'model')
15
+
16
+ os.makedirs(STATIC_FOLDER, exist_ok=True)
17
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
18
+ os.makedirs(OUTPUT_FOLDER, exist_ok=True)
19
+
20
+ # --- Model paths ---
21
+ protoPath = os.path.join(MODEL_FOLDER, 'colorization_deploy_v2.prototxt')
22
+ modelPath = os.path.join(MODEL_FOLDER, 'colorization_release_v2.caffemodel')
23
+ hullPath = os.path.join(MODEL_FOLDER, 'pts_in_hull.npy')
24
+
25
+ assert os.path.exists(protoPath), f"Missing proto file: {protoPath}"
26
+ assert os.path.exists(modelPath), f"Missing model file: {modelPath}"
27
+ assert os.path.exists(hullPath), f"Missing hull file: {hullPath}"
28
+
29
+ COLORIZATION_MODEL_AVAILABLE = False
30
+ try:
31
+ print("Loading colorization model...")
32
+ net = cv2.dnn.readNetFromCaffe(protoPath, modelPath)
33
+ pts_in_hull = np.load(hullPath)
34
+
35
+ if pts_in_hull.shape != (313, 2):
36
+ raise ValueError(f"pts_in_hull shape invalid: {pts_in_hull.shape}")
37
+
38
+ pts = pts_in_hull.transpose().reshape(2, 313, 1, 1).astype(np.float32)
39
+
40
+ net.getLayer(net.getLayerId('class8_ab')).blobs = [pts]
41
+ net.getLayer(net.getLayerId('conv8_313_rh')).blobs = [np.full([1, 313], 2.606, dtype=np.float32)]
42
+
43
+ COLORIZATION_MODEL_AVAILABLE = True
44
+ print("Colorization model loaded successfully.")
45
+ except Exception as e:
46
+ print(f"Failed to load colorization model: {e}")
47
+
48
+ MAX_DIMENSION = 2048
49
+
50
+ def resize_img(img):
51
+ h, w = img.shape[:2]
52
+ if max(h, w) > MAX_DIMENSION:
53
+ scale = MAX_DIMENSION / max(h, w)
54
+ return cv2.resize(img, (int(w * scale), int(h * scale)))
55
+ return img
56
+
57
+ def adjust_brightness_contrast(img, brightness=0, contrast=20):
58
+ alpha = 1 + contrast / 100.0
59
+ return cv2.convertScaleAbs(img, alpha=alpha, beta=brightness)
60
+
61
+ def colorize_image_local(input_path, output_path):
62
+ print(f"Reading image for colorization: {input_path}")
63
+ img = cv2.imread(input_path)
64
+ if img is None:
65
+ print("ERROR: Could not read input image (file may be corrupt or unreadable by OpenCV).")
66
+ return False
67
+ else:
68
+ print(f"Image loaded successfully, shape: {img.shape}")
69
+
70
+ if not COLORIZATION_MODEL_AVAILABLE:
71
+ print("Colorization model not available.")
72
+ return False
73
+
74
+ img = resize_img(img)
75
+ h, w = img.shape[:2]
76
+
77
+ img_rgb = img.astype("float32") / 255.0
78
+ lab = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2LAB)
79
+ L = lab[:, :, 0]
80
+
81
+ L_resized = cv2.resize(L, (224, 224))
82
+ L_resized -= 50 # mean-centering
83
+
84
+ try:
85
+ net.setInput(cv2.dnn.blobFromImage(L_resized))
86
+ ab = net.forward()[0].transpose(1, 2, 0)
87
+ except Exception as e:
88
+ print(f"ERROR during DNN forward pass: {e}")
89
+ return False
90
+
91
+ ab = cv2.resize(ab, (w, h))
92
+ out_lab = np.concatenate((L[:, :, np.newaxis], ab), axis=2)
93
+ out_bgr = cv2.cvtColor(out_lab, cv2.COLOR_Lab2BGR)
94
+ out_bgr = np.clip(out_bgr * 255, 0, 255).astype("uint8")
95
+ out_bgr = adjust_brightness_contrast(out_bgr, brightness=-10, contrast=15)
96
+ cv2.imwrite(output_path, out_bgr)
97
+ print(f"Colorized image saved to {output_path}")
98
+ return True
99
+
100
+ @app.route('/', methods=['GET', 'POST'])
101
+ def index():
102
+
103
+ print(f"protoPath: {protoPath}, exists? {os.path.exists(protoPath)}")
104
+ print(f"modelPath: {modelPath}, exists? {os.path.exists(modelPath)}")
105
+ print(f"hullPath: {hullPath}, exists? {os.path.exists(hullPath)}")
106
+ print(f"UPLOAD_FOLDER: {UPLOAD_FOLDER}, exists? {os.path.exists(UPLOAD_FOLDER)}")
107
+ print(f"OUTPUT_FOLDER: {OUTPUT_FOLDER}, exists? {os.path.exists(OUTPUT_FOLDER)}")
108
+ print(f"COLORIZATION_MODEL_AVAILABLE: {COLORIZATION_MODEL_AVAILABLE}")
109
+ print(f"cv2 version: {cv2.__version__}")
110
+
111
+ original_url = enhanced_url = None
112
+ if request.method == 'POST':
113
+ file = request.files.get('image')
114
+ if file and file.filename:
115
+ filename = secure_filename(file.filename)
116
+ orig_path = os.path.join(UPLOAD_FOLDER, filename)
117
+ print(f"Saving file to {orig_path}")
118
+ try:
119
+ file.save(orig_path)
120
+ print(f"File saved successfully.")
121
+ except Exception as e:
122
+ print(f"ERROR: Failed to save file: {e}")
123
+ return "File save failed", 400
124
+
125
+ if os.path.exists(orig_path):
126
+ print(f"Saved file size: {os.path.getsize(orig_path)} bytes")
127
+ else:
128
+ print("ERROR: File does not exist after saving!")
129
+ return "File save failed", 400
130
+
131
+ output_name = f"output_{filename}"
132
+ output_path = os.path.join(OUTPUT_FOLDER, output_name)
133
+
134
+
135
+ if not colorize_image_local(orig_path, output_path):
136
+ print("Colorization failed inside colorize_image_local")
137
+ return "Colorization failed", 400
138
+
139
+ original_url = url_for('static', filename=f'uploads/{filename}')
140
+ enhanced_url = url_for('static', filename=f'outputs/{output_name}')
141
+ else:
142
+ print("No file uploaded or empty filename.")
143
+ return "No file uploaded", 400
144
+
145
+ return render_template('index.html', original_url=original_url, enhanced_url=enhanced_url)
146
+
147
+
148
+ if __name__ == '__main__':
149
+ port = int(os.environ.get("PORT", 7860))
150
+ app.run(host='0.0.0.0', port=port, debug=False)
procfile ADDED
@@ -0,0 +1 @@
 
 
1
+ gunicorn app:app --bind 0.0.0.0:$PORT
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ Flask==3.0.3
2
+ flask-cors==4.0.1
3
+ Werkzeug==3.0.3
4
+ opencv-python==4.8.0.76
5
+ opencv-python-headless==4.8.0.76
6
+ numpy==1.26.4
templates/.DS_Store ADDED
Binary file (6.15 kB). View file
 
templates/index.html ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Image Restoration & Colorization</title>
7
+ <style>
8
+ @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap');
9
+
10
+ * {
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: 'Montserrat', sans-serif;
16
+ background: radial-gradient(circle at top left, #667eea, #764ba2, #6b46c1);
17
+ margin: 0;
18
+ padding: 40px 20px;
19
+ color: #fff;
20
+ min-height: 100vh;
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ background-attachment: fixed;
25
+ }
26
+
27
+ h1 {
28
+ font-weight: 700;
29
+ font-size: 3rem;
30
+ margin-bottom: 0.5em;
31
+ text-shadow: 0 3px 10px rgba(0,0,0,0.4);
32
+ text-align: center;
33
+ animation: fadeIn 1s ease-in-out;
34
+ }
35
+
36
+ form {
37
+ background: rgba(255, 255, 255, 0.15);
38
+ backdrop-filter: blur(10px);
39
+ border: 1px solid rgba(255,255,255,0.2);
40
+ border-radius: 16px;
41
+ padding: 35px;
42
+ max-width: 500px;
43
+ width: 100%;
44
+ box-shadow: 0 16px 32px rgba(0,0,0,0.25);
45
+ animation: slideIn 1s ease-out;
46
+ }
47
+
48
+ label {
49
+ display: block;
50
+ font-weight: 600;
51
+ margin-bottom: 10px;
52
+ margin-top: 20px;
53
+ font-size: 1.2rem;
54
+ }
55
+
56
+ input[type="file"] {
57
+ border: 2px dashed rgba(255,255,255,0.7);
58
+ background: rgba(255,255,255,0.1);
59
+ padding: 20px 14px;
60
+ border-radius: 12px;
61
+ width: 100%;
62
+ color: #f0f0f0;
63
+ font-weight: 500;
64
+ cursor: pointer;
65
+ transition: all 0.3s ease;
66
+ }
67
+
68
+ input[type="file"]:hover {
69
+ border-color: #fff;
70
+ background: rgba(255,255,255,0.15);
71
+ }
72
+
73
+ button {
74
+ margin-top: 30px;
75
+ width: 100%;
76
+ padding: 16px 0;
77
+ font-size: 1.3rem;
78
+ font-weight: 700;
79
+ color: #fff;
80
+ border: none;
81
+ border-radius: 30px;
82
+ background: linear-gradient(90deg, #ff758c, #ff7eb3);
83
+ cursor: pointer;
84
+ box-shadow: 0 8px 16px rgba(255,120,150,0.6);
85
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
86
+ }
87
+
88
+ button:hover {
89
+ transform: translateY(-3px);
90
+ box-shadow: 0 12px 24px rgba(255,150,180,0.8);
91
+ }
92
+
93
+ .preview {
94
+ margin-top: 50px;
95
+ display: flex;
96
+ justify-content: center;
97
+ gap: 30px;
98
+ flex-wrap: wrap;
99
+ max-width: 1000px;
100
+ width: 100%;
101
+ }
102
+
103
+ .preview > div {
104
+ flex: 1 1 45%;
105
+ text-align: center;
106
+ animation: fadeInUp 1s ease forwards;
107
+ }
108
+
109
+ .preview img {
110
+ max-width: 100%;
111
+ max-height: 400px;
112
+ border-radius: 16px;
113
+ box-shadow: 0 12px 28px rgba(0,0,0,0.4);
114
+ border: 4px solid rgba(255, 255, 255, 0.25);
115
+ object-fit: contain;
116
+ background: #111;
117
+ }
118
+
119
+ .preview h3 {
120
+ margin-bottom: 14px;
121
+ font-weight: 700;
122
+ font-size: 1.4rem;
123
+ text-shadow: 0 2px 6px rgba(0,0,0,0.4);
124
+ }
125
+
126
+ .download-link {
127
+ display: inline-block;
128
+ margin-top: 12px;
129
+ font-size: 1.2rem;
130
+ color: #fff;
131
+ text-decoration: none;
132
+ background: rgba(255,255,255,0.25);
133
+ padding: 10px 16px;
134
+ border-radius: 10px;
135
+ transition: background 0.3s ease, transform 0.2s ease;
136
+ }
137
+
138
+ .download-link:hover {
139
+ background: rgba(255,255,255,0.4);
140
+ transform: scale(1.05);
141
+ }
142
+
143
+ @media (max-width: 640px) {
144
+ form {
145
+ max-width: 100%;
146
+ padding: 28px 22px;
147
+ }
148
+ .preview > div {
149
+ flex-basis: 100%;
150
+ }
151
+ }
152
+
153
+ @keyframes fadeIn {
154
+ from { opacity: 0; transform: translateY(-20px); }
155
+ to { opacity: 1; transform: translateY(0); }
156
+ }
157
+
158
+ @keyframes slideIn {
159
+ from { opacity: 0; transform: translateY(40px); }
160
+ to { opacity: 1; transform: translateY(0); }
161
+ }
162
+
163
+ @keyframes fadeInUp {
164
+ from { opacity: 0; transform: translateY(20px); }
165
+ to { opacity: 1; transform: translateY(0); }
166
+ }
167
+
168
+ </style>
169
+ </head>
170
+ <body>
171
+
172
+ <h1>✨ Image Restoration &amp; Colorization</h1>
173
+
174
+ <form method="POST" enctype="multipart/form-data" novalidate>
175
+ <label for="image">Upload Damaged Image</label>
176
+ <input id="image" type="file" name="image" accept="image/*" required>
177
+
178
+ <button type="submit">✨ Enhance &amp; Colorize</button>
179
+ </form>
180
+
181
+ {% if original_url and enhanced_url %}
182
+ <section class="preview" aria-label="Image preview section">
183
+ <div>
184
+ <h3>Original Image</h3>
185
+ <img src="{{ original_url }}" alt="Original uploaded image preview" loading="lazy" />
186
+ </div>
187
+ <div>
188
+ <h3>Enhanced Image</h3>
189
+ <img src="{{ enhanced_url }}" alt="Enhanced processed image preview" loading="lazy" />
190
+ <br />
191
+ <a class="download-link" href="{{ enhanced_url }}" download>
192
+ ⬇️ Download Enhanced Image
193
+ </a>
194
+ </div>
195
+ </section>
196
+ {% endif %}
197
+
198
+ </body>
199
+ </html>