Kalhar.Pandya commited on
Commit
4e4d03e
·
0 Parent(s):

Initial commit with current state

Browse files
.gitattributes ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.jpg filter=lfs diff=lfs merge=lfs -text
37
+ *.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ "images_dataset/"
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: ComputerVision
3
+ emoji: 📊
4
+ colorFrom: indigo
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 5.15.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,477 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import hf_hub_download, login
2
+ import cv2
3
+ import numpy as np
4
+ import pickle # for loading tile features and raw images
5
+ from skimage.feature import local_binary_pattern, graycomatrix, graycoprops, hog
6
+ from skimage.metrics import structural_similarity as ssim, peak_signal_noise_ratio as psnr
7
+ from PIL import Image
8
+ import gradio as gr
9
+ import time
10
+ import os
11
+
12
+ # ---------------------------------------------------------------------
13
+ # Feature Extraction Functions
14
+ # ---------------------------------------------------------------------
15
+ def get_average_color(image):
16
+ """Compute the average color (per channel) of the image (BGR format)."""
17
+ return np.mean(image, axis=(0, 1))
18
+
19
+ def get_color_histogram(image, bins=(8, 8, 8)):
20
+ """Compute a normalized color histogram in HSV color space."""
21
+ hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
22
+ hist = cv2.calcHist([hsv], [0, 1, 2], None, bins, [0, 180, 0, 256, 0, 256])
23
+ cv2.normalize(hist, hist)
24
+ return hist.flatten()
25
+
26
+ def get_lbp_histogram(image, numPoints=24, radius=8, bins=59):
27
+ """Compute a histogram of Local Binary Patterns (LBP) from the grayscale image."""
28
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
29
+ lbp = local_binary_pattern(gray, numPoints, radius, method="uniform")
30
+ hist, _ = np.histogram(lbp.ravel(), bins=bins, range=(0, bins))
31
+ hist = hist.astype("float")
32
+ hist /= (hist.sum() + 1e-7)
33
+ return hist
34
+
35
+ def get_glcm_features(image, distances=[1, 2, 4], angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
36
+ properties=('contrast', 'dissimilarity', 'homogeneity', 'energy', 'correlation', 'ASM')):
37
+ """
38
+ Compute GLCM (Gray Level Co-occurrence Matrix) features (Haralick features).
39
+ Returns a concatenated feature vector of all requested properties, for each distance & angle.
40
+ """
41
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
42
+ glcm = graycomatrix(gray, distances=distances, angles=angles, levels=256,
43
+ symmetric=True, normed=True)
44
+ feats = []
45
+ for prop in properties:
46
+ vals = graycoprops(glcm, prop)
47
+ feats.append(vals.ravel())
48
+ return np.hstack(feats)
49
+
50
+ def get_hog_features(image, orientations=9, pixels_per_cell=(8, 8),
51
+ cells_per_block=(2, 2), block_norm='L2-Hys'):
52
+ """
53
+ Compute Histogram of Oriented Gradients (HOG) from the grayscale image.
54
+ The image is forcibly resized to 16×16 to avoid errors.
55
+ """
56
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
57
+ return hog(gray, orientations=orientations, pixels_per_cell=pixels_per_cell,
58
+ cells_per_block=(2, 2), block_norm=block_norm)
59
+
60
+ def get_combined_features(image):
61
+ """
62
+ Compute and combine all features in the following order:
63
+ - Average Color (3)
64
+ - HSV Color Histogram (512)
65
+ - LBP Histogram (59)
66
+ - GLCM Features (72)
67
+ - HOG Features (36)
68
+ Total length = 682.
69
+ """
70
+ avg_color = get_average_color(image)
71
+ color_hist = get_color_histogram(image)
72
+ lbp_hist = get_lbp_histogram(image)
73
+ glcm_feats = get_glcm_features(image)
74
+ hog_feats = get_hog_features(cv2.resize(image, (16, 16), interpolation=cv2.INTER_LINEAR))
75
+ return np.concatenate([avg_color, color_hist, lbp_hist, glcm_feats, hog_feats])
76
+
77
+ # ---------------------------------------------------------------------
78
+ # Feature Dictionary and Order
79
+ # ---------------------------------------------------------------------
80
+ FEATURES = {
81
+ "Average Color (Color, Fast)": {
82
+ "func": get_average_color,
83
+ "range": (0, 3)
84
+ },
85
+ "HSV Histogram (Color Dist., Slow)": {
86
+ "func": get_color_histogram,
87
+ "range": (3, 515)
88
+ },
89
+ "LBP Histogram (Texture, Normal)": {
90
+ "func": get_lbp_histogram,
91
+ "range": (515, 574)
92
+ },
93
+ "GLCM Features (Texture Stats, Very Slow)": {
94
+ "func": get_glcm_features,
95
+ "range": (574, 646)
96
+ },
97
+ "HOG Features (Edges/Shapes, Normal)": {
98
+ "func": lambda image: get_hog_features(cv2.resize(image, (16, 16), interpolation=cv2.INTER_LINEAR)),
99
+ "range": (646, 682)
100
+ }
101
+ }
102
+ FEATURE_ORDER = list(FEATURES.keys())
103
+
104
+ def get_selected_features(image, selected_features):
105
+ """
106
+ Compute and combine only the selected features from the image.
107
+ Uses the canonical order defined in FEATURE_ORDER.
108
+ """
109
+ feats = []
110
+ for feat in FEATURE_ORDER:
111
+ if feat in selected_features:
112
+ feats.append(FEATURES[feat]["func"](image))
113
+ if not feats:
114
+ return np.array([], dtype=np.float32)
115
+ return np.concatenate(feats).astype(np.float32)
116
+
117
+ # ---------------------------------------------------------------------
118
+ # Load Precomputed Tile Features & Raw Images
119
+ # ---------------------------------------------------------------------
120
+ try:
121
+ with open("tile_features.pkl", "rb") as f:
122
+ data = pickle.load(f)
123
+ tile_features = data["features"] # shape: (num_tiles, 682)
124
+ tile_paths = data["paths"] # e.g. "image_dataset/21837.jpg"
125
+ print(f"Loaded {len(tile_paths)} tile features from tile_features.pkl")
126
+ except Exception as e:
127
+ print("Error loading tile features from local file:", e)
128
+ tile_features = None
129
+ tile_paths = None
130
+
131
+ try:
132
+ with open("tile_images_raw.pkl", "rb") as f:
133
+ raw_images_dict = pickle.load(f)
134
+ print(f"Loaded raw images dictionary with {len(raw_images_dict)} entries.")
135
+ except Exception as e:
136
+ print("Error loading raw images dictionary:", e)
137
+ raw_images_dict = {}
138
+
139
+ def get_tile_image(tile_path):
140
+ """
141
+ Given a tile image path from the features pickle (e.g. "image_dataset\\21837.jpg"),
142
+ decode it from the raw_images_dict. Expects tile to be ~150×150.
143
+ """
144
+ fixed_path = tile_path.replace("\\", "/").strip()
145
+ if fixed_path in raw_images_dict:
146
+ raw_bytes = raw_images_dict[fixed_path]
147
+ np_arr = np.frombuffer(raw_bytes, np.uint8)
148
+ img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
149
+ if img is None:
150
+ print(f"cv2.imdecode failed for: {fixed_path}")
151
+ return img
152
+ else:
153
+ print(f"Tile image '{fixed_path}' not found.")
154
+ return None
155
+
156
+ # ---------------------------------------------------------------------
157
+ # Mosaic Generation Function (No tile scaling, with Output Scale)
158
+ # ---------------------------------------------------------------------
159
+ def mosaic_generator(user_img, block_size, output_scale=1.0,
160
+ weight_avg_color=1.0, weight_hsv_hist=1.0,
161
+ weight_lbp=1.0, weight_glcm=1.0, weight_hog=1.0):
162
+ """
163
+ Create a photomosaic using 150×150 tiles with no tile scaling.
164
+ For each block (block_size x block_size) in the cropped user image, compute the selected features
165
+ and perform a weighted linear search over the tile_features subset.
166
+
167
+ Each block is replaced by one 150×150 tile, so the final mosaic dimensions are:
168
+ (grid_rows * 150) x (grid_cols * 150).
169
+
170
+ The final mosaic is optionally rescaled by output_scale (range: 0.1 to 1.0; default 1.0).
171
+
172
+ Performance metrics (MSE, SSIM, PSNR) compare the original cropped image with a downsized version
173
+ of the mosaic.
174
+ """
175
+ start_time = time.time()
176
+
177
+ # Build a dictionary of feature weights.
178
+ feature_weights = {
179
+ "Average Color (Color, Fast)": weight_avg_color,
180
+ "HSV Histogram (Color Dist., Slow)": weight_hsv_hist,
181
+ "LBP Histogram (Texture, Normal)": weight_lbp,
182
+ "GLCM Features (Texture Stats, Very Slow)": weight_glcm,
183
+ "HOG Features (Edges/Shapes, Normal)": weight_hog
184
+ }
185
+ effective_features = [f for f in FEATURE_ORDER if feature_weights.get(f, 0) > 0]
186
+ if not effective_features:
187
+ return "Error: All features have weight = 0. Please enable at least one feature.", ""
188
+
189
+ # Build the tile_feature subset for only the selected features.
190
+ selected_indices = []
191
+ weights_list = []
192
+ for feat in FEATURE_ORDER:
193
+ if feat in effective_features:
194
+ start_idx, end_idx = FEATURES[feat]["range"]
195
+ selected_indices.extend(range(start_idx, end_idx))
196
+ w = feature_weights[feat]
197
+ weights_list.extend([w] * (end_idx - start_idx))
198
+ weights_vector = np.array(weights_list, dtype=np.float32)
199
+
200
+ if tile_features is None or tile_paths is None:
201
+ return "Error: Tile features are not loaded or incompatible.", ""
202
+ tile_subset = tile_features[:, selected_indices].astype(np.float32)
203
+
204
+ # Crop the user image to multiples of block_size.
205
+ user_img_bgr = cv2.cvtColor(np.array(user_img), cv2.COLOR_RGB2BGR)
206
+ h, w, _ = user_img_bgr.shape
207
+ new_h = (h // block_size) * block_size
208
+ new_w = (w // block_size) * block_size
209
+ user_img_bgr = user_img_bgr[:new_h, :new_w]
210
+ grid_rows = new_h // block_size
211
+ grid_cols = new_w // block_size
212
+
213
+ # Save a copy in RGB for final metrics.
214
+ original_cropped_rgb = cv2.cvtColor(user_img_bgr, cv2.COLOR_BGR2RGB)
215
+
216
+ mosaic_grid = []
217
+ progress = gr.Progress() # Row-by-row progress bar
218
+
219
+ for row in range(grid_rows):
220
+ row_tiles = []
221
+ for col in range(grid_cols):
222
+ y = row * block_size
223
+ x = col * block_size
224
+ block = user_img_bgr[y:y+block_size, x:x+block_size]
225
+
226
+ # Compute only the selected features from this block.
227
+ query_feats = get_selected_features(block, effective_features)
228
+ if query_feats.size == 0:
229
+ best_tile = np.zeros((150, 150, 3), dtype=np.uint8)
230
+ row_tiles.append(best_tile)
231
+ continue
232
+ query_feats = query_feats.reshape(1, -1)
233
+ query_weighted = query_feats * weights_vector
234
+ tile_subset_weighted = tile_subset * weights_vector
235
+
236
+ dists = np.linalg.norm(tile_subset_weighted - query_weighted, axis=1)
237
+ best_idx = np.argmin(dists)
238
+
239
+ best_tile_path = tile_paths[best_idx]
240
+ best_tile = get_tile_image(best_tile_path)
241
+ if best_tile is None:
242
+ best_tile = np.zeros((150, 150, 3), dtype=np.uint8)
243
+ else:
244
+ if best_tile.shape[:2] != (150, 150):
245
+ best_tile = cv2.resize(best_tile, (150, 150), interpolation=cv2.INTER_AREA)
246
+ row_tiles.append(best_tile)
247
+
248
+ row_image = np.hstack(row_tiles)
249
+ mosaic_grid.append(row_image)
250
+ progress((row + 1) / grid_rows, desc=f"Processed row {row+1}/{grid_rows}")
251
+
252
+ mosaic_bgr = np.vstack(mosaic_grid)
253
+ mosaic_rgb = cv2.cvtColor(mosaic_bgr, cv2.COLOR_BGR2RGB)
254
+
255
+ # Rescale mosaic output if output_scale is not 1.0.
256
+ if output_scale != 1.0:
257
+ out_w = int(mosaic_rgb.shape[1] * output_scale)
258
+ out_h = int(mosaic_rgb.shape[0] * output_scale)
259
+ mosaic_rgb = cv2.resize(mosaic_rgb, (out_w, out_h), interpolation=cv2.INTER_LINEAR)
260
+
261
+ end_time = time.time()
262
+ processing_time = end_time - start_time
263
+ total_blocks = grid_rows * grid_cols
264
+
265
+ # For performance metrics, downsize the mosaic to match original cropped dimensions.
266
+ orig_h, orig_w, _ = original_cropped_rgb.shape
267
+ mosaic_resized_for_metrics = cv2.resize(mosaic_rgb, (orig_w, orig_h), interpolation=cv2.INTER_AREA)
268
+
269
+ mse_val = np.mean((original_cropped_rgb.astype(np.float32) - mosaic_resized_for_metrics.astype(np.float32)) ** 2)
270
+ ssim_val = ssim(original_cropped_rgb, mosaic_resized_for_metrics, channel_axis=-1, win_size=3)
271
+ psnr_val = psnr(original_cropped_rgb, mosaic_resized_for_metrics)
272
+
273
+ metrics = (
274
+ f"Processing Time: {processing_time:.2f} seconds\n"
275
+ f"Grid Dimensions: {grid_rows} rows x {grid_cols} columns\n"
276
+ f"Total Blocks Processed: {total_blocks}\n"
277
+ f"MSE: {mse_val:.2f}\n"
278
+ f"SSIM: {ssim_val:.4f}\n"
279
+ f"PSNR: {psnr_val:.2f} dB\n"
280
+ )
281
+
282
+ return mosaic_rgb, metrics
283
+
284
+ # ---------------------------------------------------------------------
285
+ # Gradio Interface
286
+ # ---------------------------------------------------------------------
287
+ iface = gr.Interface(
288
+ fn=mosaic_generator,
289
+ cache_examples=False,
290
+ inputs=[
291
+ gr.Image(type="pil", label="Upload Your Image"),
292
+ gr.Slider(minimum=1, maximum=32, step=1, value=10,
293
+ label="Block Size (px) for Feature Extraction"),
294
+ gr.Slider(minimum=0.1, maximum=1.0, step=0.1, value=1.0,
295
+ label="Output Scale (0.1 to 1.0)"),
296
+ # Feature priority sliders:
297
+ gr.Slider(minimum=0.0, maximum=5.0, step=0.1, value=3.5,
298
+ label="Priority for Average Color (Fast)"),
299
+ gr.Slider(minimum=0.0, maximum=5.0, step=0.1, value=5.0,
300
+ label="Priority for HSV Histogram (Slow)"),
301
+ gr.Slider(minimum=0.0, maximum=5.0, step=0.1, value=0.2,
302
+ label="Priority for LBP Histogram (Normal)"),
303
+ gr.Slider(minimum=0.0, maximum=5.0, step=0.1, value=0.2,
304
+ label="Priority for GLCM Features (Very Slow)"),
305
+ gr.Slider(minimum=0.0, maximum=5.0, step=0.1, value=0.2,
306
+ label="Priority for HOG Features (Normal)")
307
+ ],
308
+ outputs=[
309
+ gr.Image(type="numpy", label="Mosaic Image", format="png"),
310
+ gr.Textbox(label="Performance Metrics")
311
+ ],
312
+ title="Photomosaic Generator",
313
+ description=(
314
+ "Turn your image into a mesmerizing photomosaic, crafted from carefully selected 150×150 tiles. Each block is replaced with the best-matching tile, preserving the essence of your original picture. Customize the look by adjusting feature priorities and output scale. The final mosaic captures intricate details while maintaining artistic harmony, creating a unique visual story."
315
+ ),
316
+ examples=[
317
+ # For each sample image, all examples use an output scale of 0.1.
318
+ # -- SAMPLE (1).png --
319
+ [
320
+ "samples/sample (1).png",
321
+ 10,
322
+ 0.1, # Output Scale set to 0.1
323
+ 5.0, # Priority for Average Color only
324
+ 0.0, # HSV
325
+ 0.0, # LBP
326
+ 0.0, # GLCM
327
+ 0.0 # HOG
328
+ ],
329
+ [
330
+ "samples/sample (1).png",
331
+ 10,
332
+ 0.1, # Output Scale set to 0.1
333
+ 0.0, # Priority for Average Color
334
+ 5.0, # Priority for HSV only
335
+ 0.0, # LBP
336
+ 0.0, # GLCM
337
+ 0.0 # HOG
338
+ ],
339
+ [
340
+ "samples/sample (1).png",
341
+ 10,
342
+ 0.1, # Output Scale set to 0.1
343
+ 3.5, # Combination: avg=3.5, hsv=5, rest=0.2
344
+ 5.0,
345
+ 0.2,
346
+ 0.2,
347
+ 0.2
348
+ ],
349
+ # -- SAMPLE (2).jpg --
350
+ [
351
+ "samples/sample (2).jpg",
352
+ 10,
353
+ 0.1,
354
+ 5.0,
355
+ 0.0,
356
+ 0.0,
357
+ 0.0,
358
+ 0.0
359
+ ],
360
+ [
361
+ "samples/sample (2).jpg",
362
+ 10,
363
+ 0.1,
364
+ 0.0,
365
+ 5.0,
366
+ 0.0,
367
+ 0.0,
368
+ 0.0
369
+ ],
370
+ [
371
+ "samples/sample (2).jpg",
372
+ 10,
373
+ 0.1,
374
+ 3.5,
375
+ 5.0,
376
+ 0.2,
377
+ 0.2,
378
+ 0.2
379
+ ],
380
+ # -- SAMPLE (3).jpg --
381
+ [
382
+ "samples/sample (3).jpg",
383
+ 10,
384
+ 0.1,
385
+ 5.0,
386
+ 0.0,
387
+ 0.0,
388
+ 0.0,
389
+ 0.0
390
+ ],
391
+ [
392
+ "samples/sample (3).jpg",
393
+ 10,
394
+ 0.1,
395
+ 0.0,
396
+ 5.0,
397
+ 0.0,
398
+ 0.0,
399
+ 0.0
400
+ ],
401
+ [
402
+ "samples/sample (3).jpg",
403
+ 10,
404
+ 0.1,
405
+ 3.5,
406
+ 5.0,
407
+ 0.2,
408
+ 0.2,
409
+ 0.2
410
+ ],
411
+ # -- SAMPLE (4).webp --
412
+ [
413
+ "samples/sample (4).webp",
414
+ 10,
415
+ 0.1,
416
+ 5.0,
417
+ 0.0,
418
+ 0.0,
419
+ 0.0,
420
+ 0.0
421
+ ],
422
+ [
423
+ "samples/sample (4).webp",
424
+ 10,
425
+ 0.1,
426
+ 0.0,
427
+ 5.0,
428
+ 0.0,
429
+ 0.0,
430
+ 0.0
431
+ ],
432
+ [
433
+ "samples/sample (4).webp",
434
+ 10,
435
+ 0.1,
436
+ 3.5,
437
+ 5.0,
438
+ 0.2,
439
+ 0.2,
440
+ 0.2
441
+ ],
442
+ # -- SAMPLE (5).jpg --
443
+ [
444
+ "samples/sample (5).jpg",
445
+ 10,
446
+ 0.1,
447
+ 5.0,
448
+ 0.0,
449
+ 0.0,
450
+ 0.0,
451
+ 0.0
452
+ ],
453
+ [
454
+ "samples/sample (5).jpg",
455
+ 10,
456
+ 0.1,
457
+ 0.0,
458
+ 5.0,
459
+ 0.0,
460
+ 0.0,
461
+ 0.0
462
+ ],
463
+ [
464
+ "samples/sample (5).jpg",
465
+ 10,
466
+ 0.1,
467
+ 3.5,
468
+ 5.0,
469
+ 0.2,
470
+ 0.2,
471
+ 0.2
472
+ ]
473
+ ]
474
+ )
475
+
476
+ if __name__ == "__main__":
477
+ iface.launch()
imageUpload.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import HfApi
2
+
3
+ # Create an API instance
4
+ api = HfApi()
5
+
6
+ # Start uploading the folder in the background (non-blocking)
7
+ future = api.upload_large_folder(
8
+ repo_id="kalhar/images_dataset", # Your repo ID
9
+ folder_path="C:/Users/kalha/Documents/NEU 5330/Lab 1/computer-vision-dataset/image_dataset", # Local folder to upload
10
+ repo_type="dataset", # Specify it's a dataset repo (if needed)
11
+ )
12
+
13
+ print("Upload started. Waiting for completion...")
14
+
15
+ # Optionally, you can check if the future is done
16
+ print("Upload done?", future.done())
17
+
18
+ # Block until the upload completes and get the result
19
+ result = future.result()
20
+ print("Folder uploaded successfully!")
imagesPickleCreater.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pickle
3
+
4
+ # Path to your local image dataset folder
5
+ image_folder = "C:/Users/kalha/Documents/NEU 5330/Lab 1/images_dataset" # Adjust if needed
6
+
7
+ tile_images = {}
8
+
9
+ # Iterate over all JPEG files in the folder
10
+ for filename in os.listdir(image_folder):
11
+ if filename.lower().endswith(".jpg"):
12
+ key = f"images_dataset/{filename}" # key with folder prefix
13
+ filepath = os.path.join(image_folder, filename)
14
+ with open(filepath, "rb") as f:
15
+ data = f.read() # read raw bytes without decoding
16
+ tile_images[key] = data
17
+ print(f"Stored {key}")
18
+
19
+ # Save the dictionary of raw image bytes to a pickle file
20
+ with open("tile_images_raw.pkl", "wb") as f:
21
+ pickle.dump(tile_images, f)
22
+
23
+ print("Saved tile images to tile_images_raw.pkl")
prepare_data.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2
3
+ import numpy as np
4
+ import pickle
5
+ from skimage.feature import local_binary_pattern, graycomatrix, graycoprops, hog
6
+
7
+ # ---------------------------------------------------------------------
8
+ # Feature Extraction Functions
9
+ # ---------------------------------------------------------------------
10
+ def get_average_color(image):
11
+ """Compute the average color of the image in BGR space."""
12
+ return np.mean(image, axis=(0, 1))
13
+
14
+ def get_color_histogram(image, bins=(8, 8, 8)):
15
+ """
16
+ Compute a normalized color histogram in HSV space.
17
+ """
18
+ hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
19
+ hist = cv2.calcHist([hsv], [0, 1, 2], None, bins, [0, 180, 0, 256, 0, 256])
20
+ cv2.normalize(hist, hist)
21
+ return hist.flatten()
22
+
23
+ def get_lbp_histogram(image, numPoints=24, radius=8, bins=59):
24
+ """
25
+ Compute a histogram of Local Binary Patterns (LBP) from the grayscale image.
26
+ """
27
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
28
+ lbp = local_binary_pattern(gray, numPoints, radius, method="uniform")
29
+ hist, _ = np.histogram(lbp.ravel(), bins=bins, range=(0, bins))
30
+ hist = hist.astype("float")
31
+ hist /= (hist.sum() + 1e-7)
32
+ return hist
33
+
34
+ def get_glcm_features(image,
35
+ distances=[1, 2, 4],
36
+ angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
37
+ properties=('contrast', 'dissimilarity', 'homogeneity', 'energy', 'correlation', 'ASM')):
38
+ """
39
+ Compute GLCM (Gray Level Co-occurrence Matrix) based features (a.k.a. Haralick features).
40
+ distances: List of pixel distances.
41
+ angles: List of angles in radians.
42
+ properties: GLCM properties to compute for each distance and angle.
43
+ Returns a concatenated feature vector of all properties.
44
+ """
45
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
46
+ glcm = graycomatrix(gray,
47
+ distances=distances,
48
+ angles=angles,
49
+ levels=256,
50
+ symmetric=True,
51
+ normed=True)
52
+ feats = []
53
+ for prop in properties:
54
+ vals = graycoprops(glcm, prop)
55
+ feats.append(vals.ravel()) # flatten the NxM result for this property
56
+ glcm_features = np.hstack(feats)
57
+ return glcm_features
58
+
59
+ def get_hog_features(image,
60
+ orientations=9,
61
+ pixels_per_cell=(8, 8),
62
+ cells_per_block=(2, 2),
63
+ block_norm='L2-Hys'):
64
+ """
65
+ Compute Histogram of Oriented Gradients (HOG) from the grayscale image.
66
+ By default, requires at least 16×16.
67
+ """
68
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
69
+ fd = hog(gray,
70
+ orientations=orientations,
71
+ pixels_per_cell=pixels_per_cell,
72
+ cells_per_block=cells_per_block,
73
+ block_norm=block_norm)
74
+ return fd
75
+
76
+ def get_combined_features(image):
77
+ """
78
+ Combine the average color, color histogram, LBP histogram,
79
+ GLCM-based features, and HOG features into one feature vector.
80
+
81
+ IMPORTANT: We force-resize the tile to 16×16 (for HOG)
82
+ if we want to match the mosaic script that
83
+ also forces 16×16 before HOG.
84
+ """
85
+ # -- Compute features from original image size --
86
+ avg_color = get_average_color(image)
87
+ color_hist = get_color_histogram(image)
88
+ lbp_hist = get_lbp_histogram(image)
89
+ glcm_feats = get_glcm_features(image)
90
+
91
+ # -- Force-resize to 16×16 for HOG to match mosaic script --
92
+ hog_input = cv2.resize(image, (16, 16), interpolation=cv2.INTER_LINEAR)
93
+ hog_feats = get_hog_features(hog_input)
94
+
95
+ # -- Concatenate everything --
96
+ combined = np.concatenate([
97
+ avg_color,
98
+ color_hist,
99
+ lbp_hist,
100
+ glcm_feats,
101
+ hog_feats
102
+ ])
103
+ return combined
104
+
105
+ # ---------------------------------------------------------------------
106
+ # Main Data Preparation Function
107
+ # ---------------------------------------------------------------------
108
+ def prepare_tile_data(tiles_folder, output_file):
109
+ """
110
+ Process all images in 'tiles_folder' to compute their feature vectors.
111
+ Force-resize each tile to 16×16 for HOG (same as mosaic script).
112
+ Save features + file paths to a pickle file.
113
+ """
114
+ tile_features = []
115
+ tile_paths = []
116
+ valid_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.tiff')
117
+
118
+ # Gather all valid image files
119
+ all_files = [f for f in os.listdir(tiles_folder) if f.lower().endswith(valid_extensions)]
120
+ total_files = len(all_files)
121
+
122
+ if total_files == 0:
123
+ print("No valid image files found in", tiles_folder)
124
+ return
125
+
126
+ print(f"Found {total_files} image(s) in '{tiles_folder}'. Starting feature extraction...")
127
+
128
+ for idx, filename in enumerate(all_files, start=1):
129
+ filepath = os.path.join(tiles_folder, filename)
130
+ image = cv2.imread(filepath)
131
+ if image is None:
132
+ print(f"[{idx}/{total_files}] Warning: Failed to read {filepath}")
133
+ continue
134
+
135
+ # Extract combined features (with forced 16×16 for HOG)
136
+ features = get_combined_features(image)
137
+
138
+ tile_features.append(features)
139
+ tile_paths.append(filepath)
140
+
141
+ # Log progress
142
+ print(f"[{idx}/{total_files}] Processed: {filename}")
143
+
144
+ # Convert to NumPy array (float32 for KDTree)
145
+ tile_features = np.array(tile_features, dtype=np.float32)
146
+
147
+ # Save features and paths
148
+ data = {'features': tile_features, 'paths': tile_paths}
149
+ with open(output_file, 'wb') as f:
150
+ pickle.dump(data, f)
151
+
152
+ print(f"Saved features for {len(tile_paths)} tiles to {output_file}")
153
+
154
+ # ---------------------------------------------------------------------
155
+ # Script Entry Point
156
+ # ---------------------------------------------------------------------
157
+ if __name__ == "__main__":
158
+ # Adjust as needed:
159
+ tiles_folder = "images_dataset" # Folder with tile images
160
+ output_file = "tile_features.pkl" # Pickle file for precomputed features
161
+
162
+ prepare_tile_data(tiles_folder, output_file)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ opencv-python
2
+ numpy
3
+ scikit-learn
4
+ scikit-image
5
+ Pillow
6
+ gradio
samples/sample (1).png ADDED

Git LFS Details

  • SHA256: 305a99e11f09b079da8b48691f2ac9990359a4b13ac6cca7af4f7ae4d107da6c
  • Pointer size: 131 Bytes
  • Size of remote file: 392 kB
samples/sample (2).jpg ADDED

Git LFS Details

  • SHA256: 797bbf585ee5d259be132b57c9c335e675c9a0bf8a2b9149600acaeee542b49c
  • Pointer size: 131 Bytes
  • Size of remote file: 180 kB
samples/sample (3).jpg ADDED

Git LFS Details

  • SHA256: f88b99451cf4589851cf27baab913338fb5db4b86b286124df73a01d10dd6bff
  • Pointer size: 131 Bytes
  • Size of remote file: 451 kB
samples/sample (4).webp ADDED
samples/sample (5).jpg ADDED

Git LFS Details

  • SHA256: 9df73dd5dc558116d9fcf0ec3cfffea16351560c69131c3e2f47daa14a92608c
  • Pointer size: 131 Bytes
  • Size of remote file: 519 kB
tile_features.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:61d9726b1a9097178fbe234728babb0053ac76fb9e43e8dd0ba1765e6fd046d2
3
+ size 67032135
tile_images_raw.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5135bfa6bf37af29b61509deaf06e224926a15a5177f80f8acdcb2655a21c51b
3
+ size 369696804