Project

General

Profile

Files » altmain.py

FUJITA Ryusei, 01/08/2026 01:48 PM

 
1
import cv2
2
import numpy as np
3
from scipy.special import erf
4
import config_reader
5
from typing import Tuple, Optional
6

    
7

    
8
class ProjectionSplit:
9
    """!
10
    @brief Handles splitting images for dual-projector setups with overlap blending.
11
    
12
    This class manages the process of taking a single input image, splitting it into
13
    left and right components, and applying edge blending in the overlap region
14
    to create a seamless projection when using two projectors.
15
    """
16

    
17
    def __init__(self):
18
        """!
19
        @brief Initializes the ProjectionSplit class.
20
        
21
        Sets up the configuration reader and initializes image placeholders.
22
        """
23
        self.image_left: Optional[np.ndarray] = None
24
        self.image_right: Optional[np.ndarray] = None
25
        self.image_main: Optional[np.ndarray] = None
26
        self.cfg = config_reader.ConfigReader("config.ini")
27
        print("ProjectionSplit initialized (NumPy backend)")
28

    
29
    def _generate_alpha_curves(
30
        self, overlap: int, blend_type: str
31
    ) -> Tuple[np.ndarray, np.ndarray]:
32
        """!
33
        @brief Generates alpha blending curves for the overlap region.
34

    
35
        Calculates the alpha values for the left and right images in the overlap area
36
        based on the specified blending type (linear, quadratic, or gaussian).
37

    
38
        @param overlap The width of the overlap region in pixels.
39
        @param blend_type The type of blending to apply ('linear', 'quadratic', 'gaussian').
40
        @return A tuple containing two numpy arrays: (alpha_left, alpha_right).
41
        """
42
        x = np.linspace(0, 1, overlap)
43
        #gamma = self.cfg.get_gamma()   # e.g. 0.4 ~ 1.4
44
        gamma = 1
45
    
46
        x = x ** gamma
47

    
48
        if blend_type == "linear":
49
            param = self.cfg.get_linear_parameter()
50
            left = 1 - param * x
51
            right = 1 - param + param * x
52

    
53
        elif blend_type == "quadratic":
54
            left = (1 - x) ** 2
55
            right = x ** 2
56

    
57
        elif blend_type == "gaussian":
58
            sigma = 0.25
59
            g = 0.5 * (1 + erf((x - 0.5) / (sigma * np.sqrt(2))))
60
            left = 1 - g
61
            right = g
62
        else:
63
            raise ValueError(f"Unsupported blend_type: {blend_type}")
64

    
65
        return left.astype(np.float32), right.astype(np.float32)
66

    
67
    def _apply_blending(self, image: np.ndarray, overlap: int, blend_type: str) -> None:
68
        """!
69
        @brief Applies blending to the input image and splits it.
70

    
71
        Splits the image into left and right parts and applies the calculated alpha
72
        curves to the overlap region. Saves the resulting images as 'left.png' and 'right.png'.
73

    
74
        @param image The input image as a numpy array.
75
        @param overlap The width of the overlap region in pixels.
76
        @param blend_type The type of blending to apply.
77
        """
78
        if image.shape[2] == 3:
79
            image = cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)
80

    
81
        height, width = image.shape[:2]
82
        split_x = width // 2
83

    
84
        left_end = split_x + overlap // 2
85
        right_start = split_x - overlap // 2
86

    
87
        left_img = image[:, :left_end].astype(np.float32)
88
        right_img = image[:, right_start:].astype(np.float32)
89

    
90
        alpha_l, alpha_r = self._generate_alpha_curves(overlap, blend_type)
91

    
92
        # Apply alpha blending (NumPy)
93
        left_img[:, -overlap:, 3] *= alpha_l[None, :]
94
        right_img[:, :overlap, 3] *= alpha_r[None, :]
95

    
96
        self.image_left = left_img.astype(np.uint8)
97
        self.image_right = right_img.astype(np.uint8)
98

    
99
        cv2.imwrite("left.png", self.image_left)
100
        cv2.imwrite("right.png", self.image_right)
101

    
102
    def process_images(self, overlap: int = 75, blend_type: str = "linear"):
103
        """!
104
        @brief Main processing function to load, split, and blend the image.
105

    
106
        Loads 'input.png', applies the splitting and blending logic, and stores the results.
107

    
108
        @param overlap The width of the overlap region in pixels. Default is 75.
109
        @param blend_type The type of blending to apply. Default is 'linear'.
110
        @exception FileNotFoundError Raised if 'input.png' is not found.
111
        """
112
        image = cv2.imread("input.png", cv2.IMREAD_UNCHANGED)
113
        if image is None:
114
            raise FileNotFoundError("input.png not found.")
115
        self.image_main = image
116
        self._apply_blending(image, overlap, blend_type)
(10-10/13)