import cv2 import numpy as np import gradio as gr from sklearn.cluster import KMeans from scipy.fftpack import dct, idct from skimage.morphology import skeletonize # Grayscale def to_greyscale(image): return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Negative def to_negative(image): return 255 - image # Adjust Color def adjust_color(image, r_factor=1.0, g_factor=1.0, b_factor=1.0): b, g, r = cv2.split(image) b = np.clip(b * b_factor, 0, 255).astype(np.uint8) g = np.clip(g * g_factor, 0, 255).astype(np.uint8) r = np.clip(r * r_factor, 0, 255).astype(np.uint8) return cv2.merge([b, g, r]) # Flip def flip_image(image, direction="horizontal"): flip_code = {'horizontal': 1, 'vertical': 0, 'diagonal': -1} return cv2.flip(image, flip_code.get(direction, 1)) # Translate def translate(image, x_offset, y_offset): rows, cols = image.shape[:2] M = np.float32([[1, 0, x_offset], [0, 1, y_offset]]) return cv2.warpAffine(image, M, (cols, rows)) # Scale def scale_image(image, width=None, height=None, keep_aspect_ratio=True): h, w = image.shape[:2] if keep_aspect_ratio: if width is not None: ratio = width / float(w) height = int(h * ratio) elif height is not None: ratio = height / float(h) width = int(w * ratio) if width is None: width = w if height is None: height = h return cv2.resize(image, (width, height), interpolation=cv2.INTER_AREA) # Rotate def rotate(image, angle, clockwise=True): rows, cols = image.shape[:2] center = (cols / 2, rows / 2) if clockwise: angle = -angle M = cv2.getRotationMatrix2D(center, angle, 1.0) rotated = cv2.warpAffine(image, M, (cols, rows)) return rotated # Crop def crop(image, x, y, w, h): return image[y:y+h, x:x+w] # Blend def blend(image1, image2, alpha=0.5): if image2 is None: return image1 # If No Second Image, Just Return First if image1.shape != image2.shape: image2 = cv2.resize(image2, (image1.shape[1], image1.shape[0])) return cv2.addWeighted(image1, alpha, image2, 1 - alpha, 0) # Brightness & Contrast def adjust_brightness_contrast(image, brightness=50, contrast=1.2): hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) h, s, v = cv2.split(hsv) v = np.clip(v + brightness, 0, 255).astype(np.uint8) final_hsv = cv2.merge((h, s, v)) image_brightness = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR) image_float = image_brightness.astype(np.float32) image_contrast = np.clip(contrast * (image_float - 128) + 128, 0, 255) return image_contrast.astype(np.uint8) # Color Filter def color_filter(image, lower_bound, upper_bound): hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, lower_bound, upper_bound) return cv2.bitwise_and(image, image, mask=mask) def apply_sepia(image): image_float = image.astype(np.float32) sepia_kernel = np.array([ [0.272, 0.534, 0.131], [0.349, 0.686, 0.168], [0.393, 0.769, 0.189] ]) sepia_image = image_float @ sepia_kernel.T sepia_image = np.clip(sepia_image, 0, 255) return sepia_image.astype(np.uint8) def apply_cyanotype(image): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cyan_image = np.zeros_like(image) cyan_image[:, :, 0] = np.clip(gray / 2, 0, 255) # Blue Channel cyan_image[:, :, 1] = np.clip(gray, 0, 255) # Green Channel cyan_image[:, :, 2] = 255 # Red Channel return cyan_image # Border def add_border(image, top, bottom, left, right, color_str="(0,0,0)"): color = tuple(map(int, color_str.strip("()").split(","))) return cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # Overlay def overlay(image1, image2, x, y, alpha=0.5): if image2 is None: return image1 h1, w1 = image1.shape[:2] h2, w2 = image2.shape[:2] if y + h2 > h1 or x + w2 > w1: # Resize Overlay If It Goes Beyond Boundary new_h = min(h2, h1 - y) new_w = min(w2, w1 - x) image2 = cv2.resize(image2, (new_w, new_h)) h2, w2 = new_h, new_w roi = image1[y:y+h2, x:x+w2] blended = cv2.addWeighted(roi, 1 - alpha, image2, alpha, 0) image1[y:y+h2, x:x+w2] = blended return image1 def pixelwise_operation(image1, image2, operation, brightness_factor=1.2): if operation == 'Bitwise (NOT)': # Only Needs Image1 return cv2.bitwise_not(image1) # For Other Option, We Need 2 Images if image2 is None: return image1 # Resize If Mismatch if image1.shape != image2.shape: image2 = cv2.resize(image2, (image1.shape[1], image1.shape[0])) if operation == 'Add': return cv2.add(image1, image2) elif operation == 'Subtract': return cv2.subtract(image1, image2) elif operation == 'Multiply': return cv2.multiply(image1, image2) elif operation == 'Divide': epsilon = 1e-5 image2 = image2.astype(np.float32) + epsilon image1 = image1.astype(np.float32) divided = cv2.divide(image1, image2) divided_normalized = cv2.normalize(divided, None, 0, 255, cv2.NORM_MINMAX) return cv2.convertScaleAbs(divided_normalized, alpha=brightness_factor, beta=0) elif operation == 'Bitwise (AND)': return cv2.bitwise_and(image1, image2) elif operation == 'Bitwise (OR)': return cv2.bitwise_or(image1, image2) elif operation == 'Bitwise (XOR)': return cv2.bitwise_xor(image1, image2) else: return image1 # FFT def fft_image(image: np.ndarray): if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) f = np.fft.fft2(image) fshift = np.fft.fftshift(f) magnitude = 20 * np.log(np.abs(fshift) + 1e-8) return cv2.normalize(magnitude, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) # Mean Blur def mean_blur(image: np.ndarray, ksize: int = 3): return cv2.blur(image, (ksize, ksize)) # Gaussian Blur def gaussian_blur(image: np.ndarray, ksize: int = 3, sigma: float = 1.0): if ksize % 2 == 0: ksize += 1 return cv2.GaussianBlur(image, (ksize, ksize), sigma) # Median Blur def median_blur(image: np.ndarray, ksize: int = 3): if ksize % 2 == 0: ksize += 1 return cv2.medianBlur(image, ksize) # Sobel Edge def sobel_edge(image: np.ndarray, ksize: int = 3): if ksize % 2 == 0: ksize += 1 if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=ksize) sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=ksize) magnitude = cv2.magnitude(sobelx, sobely) return np.clip(magnitude, 0, 255).astype(np.uint8) # Canny Edge def canny_edge(image: np.ndarray, t1: float, t2: float): if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) return cv2.Canny(image, t1, t2) # Laplacian Edge def laplacian_edge(image: np.ndarray, ksize: int = 3): if ksize % 2 == 0: ksize += 1 if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) lap = cv2.Laplacian(image, cv2.CV_64F, ksize=ksize) return np.clip(np.abs(lap), 0, 255).astype(np.uint8) # Histogram Equalization def histogram_equalization(image: np.ndarray): if len(image.shape) == 2: return cv2.equalizeHist(image) else: b, g, r = cv2.split(image) b_eq = cv2.equalizeHist(b) g_eq = cv2.equalizeHist(g) r_eq = cv2.equalizeHist(r) return cv2.merge([b_eq, g_eq, r_eq]) # Contrast Stretching def contrast_stretch(image: np.ndarray, in_low: int, in_high: int): img_float = image.astype(np.float32) img_stretched = (img_float - in_low) * (255.0 / max(in_high - in_low, 1e-6)) return np.clip(img_stretched, 0, 255).astype(np.uint8) # Gamma Correction def gamma_correction(image: np.ndarray, gamma: float = 1.0): inv_gamma = 1.0 / gamma table = np.array([(i / 255.0) ** inv_gamma * 255 for i in range(256)]).astype("uint8") return cv2.LUT(image, table) # RLE def rle_encode(image: np.ndarray): if len(image.shape) > 2: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) flat = image.flatten() encoding = [] prev = flat[0] count = 1 for pixel in flat[1:]: if pixel == prev: count += 1 else: encoding.append((int(prev), count)) prev = pixel count = 1 encoding.append((int(prev), count)) return encoding def rle_decode(encoding, shape): flat_image = [] for pixel_value, count in encoding: flat_image.extend([pixel_value] * count) return np.array(flat_image, dtype=np.uint8).reshape(shape) # DCT def apply_dct(image, threshold_ratio=0.01): dct_transformed = dct(dct(image.T, norm='ortho').T, norm='ortho') dct_thresh = dct_transformed * (np.abs(dct_transformed) > threshold_ratio * np.max(dct_transformed)) img_reconstructed = idct(idct(dct_thresh.T, norm='ortho').T, norm='ortho') return np.clip(img_reconstructed, 0, 255).astype(np.uint8) # Global Thresholding def global_threshold(image: np.ndarray, thresh: int = 128): if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) _, binary = cv2.threshold(image, thresh, 255, cv2.THRESH_BINARY) return binary # Adaptive Thresholding def adaptive_threshold(image: np.ndarray, block_size: int = 11, C: int = 2): if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) return cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, block_size, C) # K-Means def kmeans_segmentation(image: np.ndarray, k: int = 2): if len(image.shape) == 2: data = image.reshape((-1, 1)) else: data = image.reshape((-1, 3)) data = np.float32(data) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) _, labels, centers = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) centers = np.uint8(centers) segmented = centers[labels.flatten()] if len(image.shape) == 2: segmented = segmented.reshape((image.shape[0], image.shape[1])) else: segmented = segmented.reshape((image.shape[0], image.shape[1], 3)) return segmented # Binarize def binarize_image(image: np.ndarray, thresh: int = 127): if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) _, binary = cv2.threshold(image, thresh, 255, cv2.THRESH_BINARY) return binary # Morphological def morphological_op(binary_image: np.ndarray, op_type: str, ksize: int, iterations: int): kernel = np.ones((ksize, ksize), np.uint8) if op_type == 'erosion': return cv2.erode(binary_image, kernel, iterations=iterations) elif op_type == 'dilation': return cv2.dilate(binary_image, kernel, iterations=iterations) elif op_type == 'opening': return cv2.morphologyEx(binary_image, cv2.MORPH_OPEN, kernel, iterations=iterations) elif op_type == 'closing': return cv2.morphologyEx(binary_image, cv2.MORPH_CLOSE, kernel, iterations=iterations) else: return binary_image # Extract Boundary def extract_boundary(binary_image: np.ndarray, ksize: int = 3): kernel = np.ones((ksize, ksize), np.uint8) eroded = cv2.erode(binary_image, kernel, iterations=1) return cv2.subtract(binary_image, eroded) # Skeletonize def skeletonize_image(binary_image: np.ndarray): from skimage.morphology import skeletonize if len(binary_image.shape) == 3: binary_image = cv2.cvtColor(binary_image, cv2.COLOR_BGR2GRAY) bin_bool = (binary_image > 0) skeleton = skeletonize(bin_bool) return (skeleton * 255).astype(np.uint8) # Add Noise def add_noise(image: np.ndarray, mean=0, std=25): gauss = np.random.normal(mean, std, image.shape) noisy = image.astype(np.float32) + gauss return np.clip(noisy, 0, 255).astype(np.uint8) # Wiener Filter def wiener_filter(image: np.ndarray, ksize=5, noise_var=0.01): if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) kernel = np.ones((ksize, ksize), np.float32) / (ksize * ksize) local_mean = cv2.filter2D(image, -1, kernel) local_var = cv2.filter2D(image ** 2, -1, kernel) - (local_mean ** 2) noise_var = max(noise_var, 0.0001) result = local_mean + ((local_var - noise_var) / np.maximum(local_var, noise_var)) * (image - local_mean) return np.clip(result, 0, 255).astype(np.uint8) # Gaussian Filter def gaussian_filter_restoration(image: np.ndarray, ksize=5, sigma=1.0): if len(image.shape) == 3: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) return cv2.GaussianBlur(image, (ksize, ksize), sigma) # Inpainting def inpaint_image(image: np.ndarray, top_left, bottom_right, inpaint_radius=3): mask = np.zeros(image.shape[:2], dtype=np.uint8) r1, c1 = top_left r2, c2 = bottom_right mask[r1:r2, c1:c2] = 255 return cv2.inpaint(image, mask, inpaint_radius, cv2.INPAINT_TELEA) # Feature Detection def detect_and_compute(image: np.ndarray, method='ORB'): if len(image.shape) == 3: gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) else: gray = image if method == 'ORB': detector = cv2.ORB_create() else: try: detector = cv2.SIFT_create() except: detector = cv2.ORB_create() kp, des = detector.detectAndCompute(gray, None) return kp, des # Matching Feature def match_features(img1: np.ndarray, img2: np.ndarray, method='ORB', match_method='BF'): kp1, des1 = detect_and_compute(img1, method) kp2, des2 = detect_and_compute(img2, method) if des1 is None or des2 is None or len(des1) < 2 or len(des2) < 2: return img1 if match_method == 'BF': norm_type = cv2.NORM_HAMMING if method=='ORB' else cv2.NORM_L2 bf = cv2.BFMatcher(norm_type, crossCheck=True) matches = bf.match(des1, des2) else: if method == 'ORB': index_params = dict(algorithm=6, table_number=6, key_size=12, multi_probe_level=1) search_params = dict(checks=50) flann = cv2.FlannBasedMatcher(index_params, search_params) matches = flann.match(des1, des2) else: FLANN_INDEX_KDTREE = 1 index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) search_params = dict(checks=50) flann = cv2.FlannBasedMatcher(index_params, search_params) matches = flann.match(des1, des2) matches = sorted(matches, key=lambda x: x.distance) matched_img = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) return matched_img # Template Matching def template_match(main_img: np.ndarray, templ: np.ndarray, threshold=0.8): if len(main_img.shape) == 3: main_gray = cv2.cvtColor(main_img, cv2.COLOR_BGR2GRAY) else: main_gray = main_img if len(templ.shape) == 3: templ_gray = cv2.cvtColor(templ, cv2.COLOR_BGR2GRAY) else: templ_gray = templ result = cv2.matchTemplate(main_gray, templ_gray, cv2.TM_CCOEFF_NORMED) loc = np.where(result >= threshold) display = main_img.copy() h, w = templ_gray.shape for pt in zip(*loc[::-1]): cv2.rectangle(display, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2) return display # Tab: Basic Operations def tab_basic_ops(img1, img2, operation, r_factor, g_factor, b_factor, flip_dir, trans_x, trans_y, scale_w, scale_h, scale_keep_aspect, rot_angle, rot_clockwise, crop_x, crop_y, crop_w, crop_h, blend_alpha, bright_val, contrast_val, filter_lower_H, filter_lower_S, filter_lower_V, filter_upper_H, filter_upper_S, filter_upper_V, border_top, border_bottom, border_left, border_right, border_color_str, overlay_x, overlay_y, overlay_alpha): if img1 is None: return None try: color_tuple = tuple(map(int, border_color_str.split(','))) if len(color_tuple) != 3: color_tuple = (0, 0, 0) except: color_tuple = (0, 0, 0) if operation == "Greyscale": return to_greyscale(img1) elif operation == "Negative": return to_negative(img1) elif operation == "Adjust Color": return adjust_color(img1, r_factor, g_factor, b_factor) elif operation == "Flip": return flip_image(img1, flip_dir) elif operation == "Translate": return translate(img1, trans_x, trans_y) elif operation == "Scale": return scale_image(img1, width=scale_w, height=scale_h, keep_aspect_ratio=scale_keep_aspect) elif operation == "Rotate": return rotate(img1, rot_angle, clockwise=rot_clockwise) elif operation == "Crop": return crop(img1, crop_x, crop_y, crop_w, crop_h) elif operation == "Blend": return blend(img1, img2, alpha=blend_alpha) elif operation == "Brightness & Contrast": return adjust_brightness_contrast(img1, bright_val, contrast_val) elif operation == "Color Filter": lowerb = (filter_lower_H, filter_lower_S, filter_lower_V) upperb = (filter_upper_H, filter_upper_S, filter_upper_V) return color_filter(img1, lowerb, upperb) elif operation == "Sepia": return apply_sepia(img1) elif operation == "Cyanotype": return apply_cyanotype(img1) elif operation == "Add Border": return add_border(img1, border_top, border_bottom, border_left, border_right, color=color_tuple) elif operation == "Overlay": return overlay(img1, img2, overlay_x, overlay_y, alpha=overlay_alpha) else: return img1 # Mathematical Operations def tab_pixelwise_op(image1, image2, operation): if image1 is None: return None return pixelwise_operation(image1, image2, operation) # Transforms & Filtering def tab_transform_filter(image, operation, ksize=3, sigma=1.0, t1=50, t2=150): if image is None: return None if operation == "FFT": return fft_image(image) elif operation == "Mean Blur": return mean_blur(image, ksize) elif operation == "Gaussian Blur": return gaussian_blur(image, ksize, sigma) elif operation == "Median Blur": return median_blur(image, ksize) elif operation == "Sobel Edge": return sobel_edge(image, ksize) elif operation == "Canny Edge": return canny_edge(image, t1, t2) elif operation == "Laplacian Edge": return laplacian_edge(image, ksize) else: return image # Image Enhancement def tab_enhancement(image, operation, in_low=0, in_high=255, gamma_val=1.0): if image is None: return None if operation == "Histogram Equalization": return histogram_equalization(image) elif operation == "Contrast Stretching": return contrast_stretch(image, in_low, in_high) elif operation == "Gamma Correction": return gamma_correction(image, gamma_val) else: return image # Image Compression def tab_compression(image, operation, threshold_ratio=0.005): if image is None: return None if operation == "RLE": encoded = rle_encode(image) decoded_image = rle_decode(encoded, image.shape[:2]) return decoded_image elif operation == "DCT": compressed_image = apply_dct(image, threshold_ratio=threshold_ratio) return compressed_image else: return image # Image Segmentation def tab_segmentation(image, operation, threshold=128, block_size=11, C=2, k=3): if image is None: return None if operation == "Global Thresholding": return global_threshold(image, threshold) elif operation == "Adaptive Thresholding": return adaptive_threshold(image, block_size, C) elif operation == "K-Means": return kmeans_segmentation(image, k) else: return image # Binary Processing def tab_binary(image, operation, thresh=127, morph_op_='erosion', ksize=3, iterations=1): if image is None: return None if operation == "Binarize": return binarize_image(image, thresh) elif operation == "Morphological": bin_img = binarize_image(image, thresh=127) if len(image.shape) == 3 else image return morphological_op(bin_img, morph_op_, ksize, iterations) elif operation == "Extract Boundary": bin_img = binarize_image(image, thresh=127) if len(image.shape) == 3 else image return extract_boundary(bin_img, ksize=ksize) elif operation == "Skeletonize": bin_img = binarize_image(image, thresh=127) if len(image.shape) == 3 else image return skeletonize_image(bin_img) else: return image # Image Restoration def tab_restoration(image, operation, ksize=5, sigma=1.0, noise_var=0.01, top_left_r=0, top_left_c=0, bot_right_r=10, bot_right_c=10, inpaint_radius=3): if image is None: return None if operation == "Add Noise + Wiener Filter": noisy = add_noise(image, 0, 25) return wiener_filter(noisy, ksize, noise_var) elif operation == "Add Noise + Gaussian Filter": noisy = add_noise(image, 0, 25) return gaussian_filter_restoration(noisy, ksize, sigma) elif operation == "Inpainting": return inpaint_image(image, (top_left_r, top_left_c), (bot_right_r, bot_right_c), inpaint_radius) else: return image # Image Matching def tab_matching(image1, image2, operation, feature_method='ORB', match_method='BF', templ_thresh=0.8): if image1 is None or image2 is None: return None if operation == "Feature Detection & Matching": return match_features(image1, image2, method=feature_method, match_method=match_method) elif operation == "Template Matching": return template_match(image1, image2, threshold=templ_thresh) else: return None def build_demo(): with gr.Blocks() as demo: gr.Markdown("## Image Processing And Recognition") with gr.Tabs(): # Basic Image Operations with gr.TabItem("Basic Image Operations"): gr.Markdown("### Basic Image Operations") # Tab Greyscale with gr.TabItem("Greyscale"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") run_basic = gr.Button("Apply") run_basic.click( fn=to_greyscale, inputs=[input_image_basic1], outputs=[output_image_basic] ) # Tab Negative with gr.TabItem("Negative"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") run_basic = gr.Button("Apply") run_basic.click( fn=to_negative, inputs=[input_image_basic1], outputs=[output_image_basic] ) # Tab Adjust Color with gr.TabItem("Adjust Color"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") r_factor = gr.Slider(0.0, 2.0, value=1.0, step=0.1, label="Red Factor") g_factor = gr.Slider(0.0, 2.0, value=1.0, step=0.1, label="Green Factor") b_factor = gr.Slider(0.0, 2.0, value=1.0, step=0.1, label="Blue Factor") run_basic = gr.Button("Apply") run_basic.click( fn=adjust_color, inputs=[input_image_basic1, r_factor, g_factor, b_factor], outputs=[output_image_basic] ) # Tab Flip with gr.TabItem("Flip"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") flip_dir = gr.Dropdown(["horizontal", "vertical", "diagonal"], value="horizontal", label="Flip Direction") run_basic = gr.Button("Apply") run_basic.click( fn=flip_image, inputs=[input_image_basic1, flip_dir], outputs=[output_image_basic] ) # Tab Translate with gr.TabItem("Translate"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") trans_x = gr.Slider(-200, 200, value=0, step=1, label="Translate X") trans_y = gr.Slider(-200, 200, value=0, step=1, label="Translate Y") run_basic = gr.Button("Apply") run_basic.click( fn=translate, inputs=[input_image_basic1, trans_x, trans_y], outputs=[output_image_basic] ) # Tab Scale with gr.TabItem("Scale"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") scale_w = gr.Number(value=None, label="Scale Width (None=auto)") scale_h = gr.Number(value=None, label="Scale Height (None=auto)") scale_keep_aspect = gr.Checkbox(value=True, label="Keep Aspect Ratio") run_basic = gr.Button("Apply") run_basic.click( fn=scale_image, inputs=[input_image_basic1, scale_w, scale_h, scale_keep_aspect], outputs=[output_image_basic] ) # Tab Rotate with gr.TabItem("Rotate"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") rot_angle = gr.Slider(-180, 180, value=0, step=1, label="Rotate Angle") rot_clockwise = gr.Checkbox(value=True, label="Rotate Clockwise") run_basic = gr.Button("Apply") run_basic.click( fn=rotate, inputs=[input_image_basic1, rot_angle, rot_clockwise], outputs=[output_image_basic] ) # Tab Crop with gr.TabItem("Crop"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") crop_x = gr.Slider(0, 300, value=0, step=1, label="Crop X") crop_y = gr.Slider(0, 300, value=0, step=1, label="Crop Y") crop_w = gr.Slider(0, 300, value=100, step=1, label="Crop Width") crop_h = gr.Slider(0, 300, value=100, step=1, label="Crop Height") run_basic = gr.Button("Apply") run_basic.click( fn=crop, inputs=[input_image_basic1, crop_x, crop_y, crop_w, crop_h], outputs=[output_image_basic] ) # Tab Blend with gr.TabItem("Blend"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") input_image_basic2 = gr.Image(label="Input Image 2 (for blend)") output_image_basic = gr.Image(label="Output Image") blend_alpha = gr.Slider(0.0, 1.0, value=0.5, step=0.05, label="Blend Alpha") run_basic = gr.Button("Apply") run_basic.click( fn=blend, inputs=[input_image_basic1, input_image_basic2, blend_alpha], outputs=[output_image_basic] ) # Tab Brightness & Contrast with gr.TabItem("Brightness & Contrast"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") bright_val = gr.Slider(-100, 100, value=50, step=1, label="Brightness") contrast_val = gr.Slider(0.1, 3.0, value=1.2, step=0.1, label="Contrast") run_basic = gr.Button("Apply") run_basic.click( fn=adjust_brightness_contrast, inputs=[input_image_basic1, bright_val, contrast_val], outputs=[output_image_basic] ) # Tab Color Filter with gr.TabItem("Color Filter"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") filter_type = gr.Radio( ["Custom", "Sepia", "Cyanotype"], label="Select Filter Type", value="Custom", ) filter_lower_H = gr.Slider(0, 179, value=0, step=1, label="Filter Lower H") filter_lower_S = gr.Slider(0, 255, value=0, step=1, label="Filter Lower S") filter_lower_V = gr.Slider(0, 255, value=0, step=1, label="Filter Lower V") filter_upper_H = gr.Slider(0, 179, value=179, step=1, label="Filter Upper H") filter_upper_S = gr.Slider(0, 255, value=255, step=1, label="Filter Upper S") filter_upper_V = gr.Slider(0, 255, value=255, step=1, label="Filter Upper V") run_basic = gr.Button("Apply") def apply_selected_filter(image, filter_type, lower_H, lower_S, lower_V, upper_H, upper_S, upper_V): if filter_type == "Custom": lowerb = (lower_H, lower_S, lower_V) upperb = (upper_H, upper_S, upper_V) return color_filter(image, lowerb, upperb) elif filter_type == "Sepia": return apply_sepia(image) elif filter_type == "Cyanotype": return apply_cyanotype(image) run_basic.click( fn=apply_selected_filter, inputs=[input_image_basic1, filter_type, filter_lower_H, filter_lower_S, filter_lower_V, filter_upper_H, filter_upper_S, filter_upper_V], outputs=[output_image_basic] ) # Tab Add Border with gr.TabItem("Add Border"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") output_image_basic = gr.Image(label="Output Image") border_top = gr.Slider(0, 100, value=0, step=1, label="Border Top") border_bottom = gr.Slider(0, 100, value=0, step=1, label="Border Bottom") border_left = gr.Slider(0, 100, value=0, step=1, label="Border Left") border_right = gr.Slider(0, 100, value=0, step=1, label="Border Right") border_color_str = gr.Textbox(value="0,0,0", label="Border Color (R,G,B)") run_basic = gr.Button("Apply") run_basic.click( fn=add_border, inputs=[input_image_basic1, border_top, border_bottom, border_left, border_right, border_color_str], outputs=[output_image_basic] ) # Tab Overlay with gr.TabItem("Overlay"): with gr.Row(): input_image_basic1 = gr.Image(label="Input Image 1") input_image_basic2 = gr.Image(label="Input Image 2 (for overlay)") output_image_basic = gr.Image(label="Output Image") overlay_x = gr.Slider(0, 300, value=0, step=1, label="Overlay X") overlay_y = gr.Slider(0, 300, value=0, step=1, label="Overlay Y") overlay_alpha = gr.Slider(0.0, 1.0, value=0.5, step=0.05, label="Overlay Alpha") run_basic = gr.Button("Apply") run_basic.click( fn=overlay, inputs=[input_image_basic1, input_image_basic2, overlay_x, overlay_y, overlay_alpha], outputs=[output_image_basic] ) # Mathematical Operations with gr.TabItem("Mathematical Operations"): gr.Markdown("### Mathematical Operations on Images") with gr.Row(): input_image_math1 = gr.Image(label="Input Image 1") input_image_math2 = gr.Image(label="Input Image 2 (ignored if NOT)") output_image_math = gr.Image(label="Output Image") operation_math = gr.Radio( choices=["Add", "Subtract", "Multiply", "Divide", "Bitwise (AND)", "Bitwise (OR)", "Bitwise (XOR)", "Bitwise (NOT)"], value="add", label="Pixelwise Operation" ) run_math = gr.Button("Apply Operation") run_math.click( tab_pixelwise_op, inputs=[input_image_math1, input_image_math2, operation_math], outputs=[output_image_math] ) # Transforms & Filtering with gr.TabItem("Transforms & Filtering"): gr.Markdown("### Transforms & Filtering") with gr.Row(): input_image_tf = gr.Image(type="numpy", label="Input Image") # Ensure 'numpy' type for the input image output_image_tf = gr.Image(type="numpy", label="Output Image") # Ensure 'numpy' type for the output image # Dropdown to choose operation operation_tf = gr.Radio( choices=["FFT", "Mean Blur", "Gaussian Blur", "Median Blur", "Sobel Edge", "Canny Edge", "Laplacian Edge"], value="FFT", label="Select Operation" ) # Sliders for kernel size, sigma, and Canny thresholds ksize_tf = gr.Slider(1, 15, step=1, value=3, label="Kernel Size (blur/edge)") sigma_tf = gr.Slider(0.1, 5.0, step=0.1, value=1.0, label="Sigma (Gaussian)") t1_tf = gr.Slider(0, 255, value=50, step=1, label="Canny Threshold1") t2_tf = gr.Slider(0, 255, value=150, step=1, label="Canny Threshold2") run_tf = gr.Button("Process") def _process_tf(img, op, k, s, c1, c2): return tab_transform_filter(img, op, k, s, c1, c2) # Set up the button click interaction run_tf.click(_process_tf, inputs=[input_image_tf, operation_tf, ksize_tf, sigma_tf, t1_tf, t2_tf], outputs=[output_image_tf]) # Enhancement with gr.TabItem("Enhancement"): gr.Markdown("### Image Enhancement") with gr.Row(): input_image_en = gr.Image(label="Input Image") output_image_en = gr.Image(label="Output Image") operation_en = gr.Radio( choices=["Histogram Equalization", "Contrast Stretching", "Gamma Correction"], value="Histogram Equalization", label="Select Enhancement" ) in_low_en = gr.Slider(0, 255, value=0, step=1, label="In Low (Contrast Stretch)") in_high_en = gr.Slider(0, 255, value=255, step=1, label="In High (Contrast Stretch)") gamma_en = gr.Slider(0.1, 5.0, value=1.0, step=0.1, label="Gamma") run_en = gr.Button("Enhance") def _process_en(img, op, low, high, gm): return tab_enhancement(img, op, low, high, gm) run_en.click(_process_en, inputs=[input_image_en, operation_en, in_low_en, in_high_en, gamma_en], outputs=[output_image_en]) # Compression with gr.TabItem("Compression"): gr.Markdown("### Image Compression") with gr.Row(): input_image_comp = gr.Image(label="Input Image") output_comp_image = gr.Image(label="Output Image", interactive=False) operation_comp = gr.Radio( choices=["RLE", "DCT"], value="RLE", label="Select Compression" ) run_comp = gr.Button("Compress") def _process_comp(img, op): result = tab_compression(img, op) return result run_comp.click( _process_comp, inputs=[input_image_comp, operation_comp], outputs=[output_comp_image] ) # Tab: Segmentation with gr.TabItem("Segmentation"): gr.Markdown("### Image Segmentation") with gr.Row(): input_image_seg = gr.Image(label="Input Image") output_image_seg = gr.Image(label="Output Image") operation_seg = gr.Radio( choices=["Global Thresholding", "Adaptive Thresholding", "K-Means"], value="Global Thresholding", label="Select Segmentation" ) thresh_seg = gr.Slider(0, 255, value=128, step=1, label="Threshold (Global)") block_seg = gr.Slider(3, 31, step=2, value=11, label="Block Size (Adaptive)") c_seg = gr.Slider(0, 10, value=2, step=1, label="C (Adaptive)") k_seg = gr.Slider(2, 10, value=3, step=1, label="K (K-Means)") run_seg = gr.Button("Segment") def _process_seg(img, op, th, bs, c_, k_): return tab_segmentation(img, op, th, bs, c_, k_) run_seg.click(_process_seg, inputs=[input_image_seg, operation_seg, thresh_seg, block_seg, c_seg, k_seg], outputs=[output_image_seg]) # Tab: Binary Processing with gr.TabItem("Binary Processing"): gr.Markdown("### Binary Image Processing") with gr.Row(): input_image_bin = gr.Image(label="Input Image") output_image_bin = gr.Image(label="Output Image") operation_bin = gr.Radio( choices=["Binarize", "Morphological", "Extract Boundary", "Skeletonize"], value="Binarize", label="Select Operation" ) thresh_bin = gr.Slider(0, 255, value=127, step=1, label="Threshold") morph_op_bin = gr.Dropdown( choices=["erosion", "dilation", "opening", "closing"], value="erosion", label="Morphological Operation" ) ksize_bin = gr.Slider(1, 15, value=3, step=1, label="Kernel Size") iter_bin = gr.Slider(1, 10, value=1, step=1, label="Iterations") run_bin = gr.Button("Process Binary") def _process_bin(img, op, th, mop, ks, iters): return tab_binary(img, op, th, mop, ks, iters) run_bin.click(_process_bin, inputs=[input_image_bin, operation_bin, thresh_bin, morph_op_bin, ksize_bin, iter_bin], outputs=[output_image_bin]) # Tab: Restoration with gr.TabItem("Restoration"): gr.Markdown("### Image Restoration") with gr.Row(): input_image_rest = gr.Image(label="Input Image") output_image_rest = gr.Image(label="Output Image") operation_rest = gr.Radio( choices=["Add Noise + Wiener Filter", "Add Noise + Gaussian Filter", "Inpainting"], value="Add Noise + Wiener Filter", label="Select Restoration" ) ksize_rest = gr.Slider(1, 15, value=5, step=1, label="Kernel Size (Wiener/Gaussian)") sigma_rest = gr.Slider(0.1, 5.0, value=1.0, step=0.1, label="Sigma (Gaussian)") noise_var_rest = gr.Slider(0.001, 1.0, value=0.01, step=0.01, label="Noise Var (Wiener)") top_left_r = gr.Number(value=0, label="Inpaint Top Row") top_left_c = gr.Number(value=0, label="Inpaint Left Col") bot_right_r = gr.Number(value=50, label="Inpaint Bottom Row") bot_right_c = gr.Number(value=50, label="Inpaint Right Col") inpaint_rad = gr.Slider(1, 10, value=3, step=1, label="Inpaint Radius") run_rest = gr.Button("Restore") def _process_rest(img, op, ks, sg, nv, r1, c1, r2, c2, ipr): return tab_restoration(img, op, ks, sg, nv, int(r1), int(c1), int(r2), int(c2), ipr) run_rest.click(_process_rest, inputs=[input_image_rest, operation_rest, ksize_rest, sigma_rest, noise_var_rest, top_left_r, top_left_c, bot_right_r, bot_right_c, inpaint_rad], outputs=[output_image_rest]) # Tab: Matching with gr.TabItem("Matching"): gr.Markdown("### Image Matching") with gr.Row(): input_image_match1 = gr.Image(label="Main Image / Image1") input_image_match2 = gr.Image(label="Template / Image2") output_image_match = gr.Image(label="Output Image") operation_match = gr.Radio( choices=["Feature Detection & Matching", "Template Matching"], value="Feature Detection & Matching", label="Select Matching Operation" ) feature_method = gr.Dropdown(choices=["ORB", "SIFT"], value="ORB", label="Feature Method") match_method = gr.Dropdown(choices=["BF", "FLANN"], value="BF", label="Match Method") templ_thresh = gr.Slider(0.0, 1.0, value=0.8, step=0.01, label="Template Threshold") run_match = gr.Button("Match") def _process_match(img1, img2, op, fm, mm, thr): return tab_matching(img1, img2, op, fm, mm, thr) run_match.click(_process_match, inputs=[input_image_match1, input_image_match2, operation_match, feature_method, match_method, templ_thresh], outputs=[output_image_match]) return demo if __name__ == "__main__": demo = build_demo() demo.launch(share=True)