Project

General

Profile

Code » History » Version 2

VALECHA Bharat, 01/07/2026 08:59 PM

1 2 VALECHA Bharat
[[Wiki|Home]]  |  [[Project Details|Project Details]]  |  [[Group Members|Group Members]]  |  [[UML Diagrams|UML Diagrams]] |  [[Weekly Progress|Weekly Progress]]  |  **[[Code|Code]]**  |  [[Results|Results]]
2
3
---
4
5
> h1. Code
6
7
*config_reader.py*
8
9
<pre><code class="python">
10
11
#!/usr/bin/env python
12
# -*- coding: utf-8 -*-
13
# ˅
14
import json
15
import os
16
# ˄
17
18
19
class ConfigReader(object):
20
    # ˅
21
    CONFIG_FILENAME = "config.json"
22
    # ˄
23
24
    def __init__(self):
25
        self.__config = {}
26
        # ˅
27
        self._load_config()
28
        # ˄
29
30
    # ˅
31
    def _load_config(self):
32
        """Loads the configuration from the JSON file."""
33
        if not os.path.exists(self.CONFIG_FILENAME):
34
            print(f"Warning: {self.CONFIG_FILENAME} not found. Using defaults.")
35
            return
36
37
        with open(self.CONFIG_FILENAME, 'r') as f:
38
            self.__config = json.load(f)
39
    # ˄
40
41
    def getProjectedImageWidth(self):
42
        # ˅
43
        # The physical width of the image projected by ONE projector
44
        return float(self.__config.get("projected_image_width", 0))
45
        # ˄
46
47
    def getDistanceBetweenProjectors(self):
48
        # ˅
49
        # The physical distance between the lenses of the two projectors
50
        return float(self.__config.get("distance_between_projectors", 0))
51
        # ˄
52
53
    def getImageWidth(self):
54
        # ˅
55
        # The pixel width of the source image file
56
        return int(self.__config.get("image_width", 1920))
57
        # ˄
58
59
    def getImageHeight(self):
60
        # ˅
61
        # The pixel height of the source image file
62
        return int(self.__config.get("image_height", 1080))
63
        # ˄
64
65
    def getImageName(self):
66
        # ˅
67
        return self.__config.get("image_name", "")
68
        # ˄
69
70
    def getSide(self):
71
        # ˅
72
        # 'left' or 'right'
73
        return self.__config.get("side", "left").lower()
74
        # ˄
75
76
    def getGamma(self):
77
        # ˅
78
        # Usually 2.2 for standard displays
79
        return float(self.__config.get("gamma", 2.2))
80
        # ˄
81
</code></pre>
82
83
*config.json*
84
85
<pre><code class="python">
86
87
{
88
    "image_name": "right.jpg",
89
    "image_width": 1920,
90
    "image_height": 1080,
91
    "projected_image_width": 200,
92
    "distance_between_projectors": 150,
93
    "gamma": 3,
94
    "side": "right"
95
}
96
</code></pre>
97
98
*graph_gen _IND.py*
99
100
<pre><code class="python">
101
102
import numpy as np
103
import matplotlib.pyplot as plt
104
105
106
def generate_individual_graphs():
107
    # Input gradient (0 to 1)
108
    x = np.linspace(0, 1, 500)
109
110
    # The three specified Gamma values
111
    gamma_values = [0.5, 3, 50]
112
113
    for gamma in gamma_values:
114
        plt.figure(figsize=(8, 6))
115
116
        # 1. Reference Line (Linear - No Correction)
117
        # This is the 'Reference Curve'. It shows the output without blending/correction.
118
        plt.plot(x, x, 'k--', label='Linear Reference (No Correction)', alpha=0.5)
119
120
        # 2. Gamma Correction Curve
121
        # Logic: y = x^(1/gamma)
122
        y = np.power(x, 1.0 / gamma)
123
124
        # Plotting the curve
125
        plt.plot(x, y, color='blue', linewidth=3, label=f'Gamma Correction (γ={gamma})')
126
127
        # Decoration
128
        plt.title(f'Gamma Correction Curve: γ = {gamma}', fontsize=14)
129
        plt.xlabel('Input Pixel Intensity (0 to 1)', fontsize=12)
130
        plt.ylabel('Corrected Output Intensity', fontsize=12)
131
        plt.legend(loc='best')
132
        plt.grid(True, alpha=0.3)
133
        plt.xlim(0, 1.0)
134
        plt.ylim(0, 1.05)
135
136
        # Saving separate files for each gamma
137
        filename = f"gamma_curve_{gamma}.png"
138
        plt.savefig(filename)
139
        print(f"Generated graph: {filename}")
140
141
        # Close plot to start fresh for next gamma
142
        plt.close()
143
144
145
if __name__ == "__main__":
146
    generate_individual_graphs()
147
148
</code></pre>
149
150
*graph_gen.py*
151
152
<pre><code class="python">
153
154
import numpy as np
155
import matplotlib.pyplot as plt
156
157
158
def plot_gamma_curves():
159
    # Generate input gradient values from 0 to 1
160
    x = np.linspace(0, 1, 500)
161
162
    # Defined gamma values for comparison
163
    gamma_values = [0.5, 3, 50]
164
165
    plt.figure(figsize=(10, 6))
166
167
    # Reference Line (Linear - No Correction)
168
    plt.plot(x, x, 'k--', label='Linear (No Correction)', alpha=0.5)
169
170
    # Blending logic: y = x^(1/gamma)
171
    for gamma in gamma_values:
172
        # Formula derived from the provided code
173
        y = np.power(x, 1.0 / gamma)
174
175
        # Plotting
176
        plt.plot(x, y, linewidth=2.5, label=f'Gamma = {gamma} (Exp: 1/{gamma} ≈ {1.0 / gamma:.2f})')
177
178
    # Graph Formatting
179
    plt.title('Gamma Correction Curves Comparison', fontsize=14)
180
    plt.xlabel('Input Value (Gradient 0 to 1)', fontsize=12)
181
    plt.ylabel('Corrected Output Value', fontsize=12)
182
    plt.legend()
183
    plt.grid(True, alpha=0.3)
184
    plt.ylim(0, 1.05)
185
    plt.xlim(0, 1.0)
186
187
    # Save chart
188
    output_filename = 'gamma_comparison_graph.png'
189
    plt.savefig(output_filename)
190
    print(f"Graph successfully saved as: {output_filename}")
191
    plt.show()
192
193
194
if __name__ == "__main__":
195
    plot_gamma_curves()
196
197
</code></pre>
198
199
*main_alpha_blender.py*
200
201
<pre><code class="python">
202
203
#!/usr/bin/env python
204
# -*- coding: utf-8 -*-
205
# ˅
206
import cv2
207
import numpy as np
208
from config_reader import ConfigReader
209
210
211
# ˄
212
213
214
class MainAlphaBlender(object):
215
    # ˅
216
217
    # ˄
218
219
    def __init__(self):
220
        self.__configReader = None
221
        # ˅
222
        self.__configReader = ConfigReader()
223
        # ˄
224
225
    # ˅
226
    def run(self):
227
        print("--- Starting Alpha Blend Process (Gamma Corrected) ---")
228
229
        # 1. Get Configuration
230
        image_name = self.__configReader.getImageName()
231
        side = self.__configReader.getSide()
232
        proj_width_phys = self.__configReader.getProjectedImageWidth()
233
        dist_phys = self.__configReader.getDistanceBetweenProjectors()
234
        gamma = self.__configReader.getGamma()
235
236
        # 2. Load Image
237
        img = cv2.imread(image_name, cv2.IMREAD_UNCHANGED)
238
        if img is None:
239
            print(f"Error: Could not load image '{image_name}'")
240
            return
241
242
        # Ensure image is BGRA
243
        if img.shape[2] == 3:
244
            img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
245
246
        height, width = img.shape[:2]
247
248
        # 3. Calculate Overlap
249
        if proj_width_phys > 0:
250
            overlap_ratio = 1.0 - (dist_phys / proj_width_phys)
251
        else:
252
            overlap_ratio = 0.0
253
254
        if overlap_ratio <= 0:
255
            print("Warning: No overlap detected.")
256
            return
257
258
        overlap_pixels = int(width * overlap_ratio)
259
        print(f"Processing '{side}' | Overlap: {overlap_pixels} pixels | Gamma: {gamma}")
260
261
        # 4. Generate Mask
262
        # Create a linear ramp from 0 to 1
263
        linear_ramp = np.linspace(0, 1, overlap_pixels)
264
265
        # Determine the base curve direction BEFORE gamma
266
        if side == "left":
267
            # Left image fades OUT (1 -> 0) on the right side
268
            base_curve = 1.0 - linear_ramp
269
        elif side == "right":
270
            # Right image fades IN (0 -> 1) on the left side
271
            base_curve = linear_ramp
272
        else:
273
            print("Error: Side must be 'left' or 'right'")
274
            return
275
276
        # 5. Apply Gamma Correction
277
        # This "boosts" the midtones. 50% gray becomes ~73% gray.
278
        # This is crucial because 0.73^2.2 (projector gamma) + 0.73^2.2 = ~1.0 Light
279
        mask_curve = np.power(base_curve, 1 / gamma)
280
281
        # 6. Apply to Image
282
        alpha_channel = img[:, :, 3].astype(float) / 255.0
283
        mask_block = np.tile(mask_curve, (height, 1))
284
285
        if side == "left":
286
            # Apply to the right-most columns
287
            alpha_channel[:, width - overlap_pixels:] *= mask_block
288
        elif side == "right":
289
            # Apply to the left-most columns
290
            alpha_channel[:, :overlap_pixels] *= mask_block
291
292
        # 7. Save Output
293
        img[:, :, 3] = (alpha_channel * 255).astype(np.uint8)
294
295
        # Optional: Burn transparency into RGB for easier debugging/viewing
296
        # (This makes the transparent parts black, ensuring no 'ghosting' if alpha is ignored)
297
        for c in range(3):
298
            if side == "left":
299
                roi = img[:, :, c][:, width - overlap_pixels:]
300
                img[:, :, c][:, width - overlap_pixels:] = (roi * mask_block).astype(np.uint8)
301
            else:
302
                roi = img[:, :, c][:, :overlap_pixels]
303
                img[:, :, c][:, :overlap_pixels] = (roi * mask_block).astype(np.uint8)
304
305
        output_name = f"output_{side}.png"
306
        cv2.imwrite(output_name, img)
307
        print(f"Saved: {output_name}")
308
309
    # ˄
310
311
312
# ˅
313
if __name__ == "__main__":
314
    blender = MainAlphaBlender()
315
    blender.run()
316
# ˄
317
318
</code></pre>
319
320
*x_curve.py*
321
322
<pre><code class="python">
323
import numpy as np
324
import matplotlib.pyplot as plt
325
326
327
def plot_blending_mechanics_unique():
328
    # Setup - Use your specific project values here if you have them
329
    overlap_pixels = 256  # Example: Change this to your actual overlap width
330
    x_pixels = np.linspace(0, overlap_pixels, 500)
331
    x_normalized = np.linspace(0, 1, 500)
332
333
    # 1. Linear Alpha (The "Wrong" Way)
334
    alpha_left_lin = 1.0 - x_normalized
335
    alpha_right_lin = x_normalized
336
337
    # 2. Gamma Corrected Alpha (Your Solution)
338
    gamma = 2.2  # Your specific gamma
339
    alpha_left_corr = np.power(alpha_left_lin, 1.0 / gamma)
340
    alpha_right_corr = np.power(alpha_right_lin, 1.0 / gamma)
341
342
    plt.figure(figsize=(10, 6))
343
344
    # Plot Gamma Corrected (Solid Colors) - The "Hero" of the graph
345
    plt.plot(x_pixels, alpha_left_corr, 'b-', linewidth=3, label='Left Projector Output')
346
    plt.plot(x_pixels, alpha_right_corr, 'r-', linewidth=3, label='Right Projector Output')
347
348
    # Plot Linear (Dashed) - The "Baseline"
349
    plt.plot(x_pixels, alpha_left_lin, 'k:', linewidth=1.5, alpha=0.5, label='Linear Reference (No Correction)')
350
    plt.plot(x_pixels, alpha_right_lin, 'k:', linewidth=1.5, alpha=0.5)
351
352
    # Unique Touch: Shade the area to show "Light Energy"
353
    plt.fill_between(x_pixels, alpha_left_corr, alpha_left_lin, color='blue', alpha=0.1)
354
    plt.fill_between(x_pixels, alpha_right_corr, alpha_right_lin, color='red', alpha=0.1)
355
356
    # Annotations specific to your analysis
357
    plt.text(overlap_pixels / 2, 0.8, 'Gamma Boost Region\n(Corrects Dark Band)',
358
             horizontalalignment='center', fontsize=10,
359
             bbox=dict(facecolor='white', alpha=0.8, edgecolor='none'))
360
361
    plt.title(f'Spatial Intensity Distribution (Overlap: {overlap_pixels}px)', fontsize=14, fontweight='bold')
362
    plt.xlabel('Pixel Position in Overlap Zone', fontsize=12)
363
    plt.ylabel('Projected Light Intensity (0.0 - 1.0)', fontsize=12)
364
    plt.legend()
365
    plt.grid(True, alpha=0.3)
366
367
    plt.savefig('custom_blending_curve.png', dpi=100)
368
    print("Saved: custom_blending_curve.png")
369
370
371
if __name__ == "__main__":
372
    plot_blending_mechanics_unique()
373
374
</code></pre>