使用OpenCV更改图像一部分的色温,使用图像的其余部分

5lhxktic  于 2023-06-24  发布在  其他
关注(0)|答案(1)|浏览(299)

我有一个房间的图像,有一个打开的门,我们可以看到另一个房间。
拍摄照片的房间的白色平衡是正确的,但在另一个房间它是关闭的,因为照明是不同的。
我想把正确的白色从原始图像(我使用了一个蒙版)Map到另一个房间的像素(我也有一个蒙版)。
下面是我的代码:

cv::Mat blueMask;
cv::Mat whiteMask;
cv::Mat hsv;
getWhiteColorMask(src, blueMask, whiteMask, hsv);

// Save the HSV image
bool success = cv::imwrite(outputImagePath + "hsv.jpg", hsv);
// Save the white mask image
success = cv::imwrite(outputImagePath + "white_mask.jpg", whiteMask);
success = cv::imwrite(outputImagePath + "blue_mask.jpg", blueMask);
// Apply changes to the blue channel based on the mask
cv::Mat adjustedImage = src.clone();  // Clone the original image for adjustment

for (int row = 0; row < src.rows; ++row) {
    for (int col = 0; col < src.cols; ++col) {
        // Check if the pixel is in the blue mask
        if (blueMask.at<uchar>(row, col) > 0) {
            // Get the corresponding pixel in the white mask
            cv::Vec3b whitePixel = whiteMask.at<cv::Vec3b>(row, col);
        
            // Adjust the pixel in the blue mask using the white color
            cv::Vec3b& bluePixel = adjustedImage.at<cv::Vec3b>(row, col);
            bluePixel[0] = whitePixel[0];  // B channel
            //bluePixel[1] = whitePixel[1];  // G channel
            //bluePixel[2] = whitePixel[2];  // R channel
        }
    }
}
// Save the modified image with the new file name
std::string newImagePath = "./mask_test/white_masks/adjustedImage.jpg";
success = cv::imwrite(newImagePath, adjustedImage);

我已经删除了所有的验证打印,使代码更短,所以不要打扰我使用的布尔成功
以下是理解问题所需的所有图像:
来源图片:

白色像素遮罩不正确:

正确的白色像素遮罩:

HSV图像:

xv8emn3q

xv8emn3q1#

一般来说,我们必须校正红色/绿色和蓝色/绿色的颜色比率,以匹配另一侧的比率(“白色”的比率)。
没有一个确定性的解决方案适用于所有情况,我们必须使用启发式方法来找到上述每一侧的比率。
为了找到白色(灰色)的比率,我们可以使用白色平衡算法作为Grayworld assumption
在我的解决方案中,我使用的是“最大RGB”算法的变体(假设R、G、B的高百分位数代表白色像素)。
当应用颜色校正时,RGB值被假定在线性空间中(没有伽马)。
首先,我们应该做的是从sRGB转换到线性RGB颜色空间(反相伽马)。
我们还可以修复掩码以更好地表示左侧和右侧(出于测试目的,我们可以假设我们知道如何完美地分割左侧/右侧)。
在反转伽马并固定掩模之后,我们可以使用以下阶段:

  • 从RGB图像中提取红、绿色、蓝颜色通道。
  • 创建一个未饱和像素的遮罩(“刻录”)-我们希望从统计数据中排除饱和像素。
  • 使用蒙版提取左侧的所有红色、绿色、蓝色像素(也未饱和)。

使用蒙版提取右侧的所有红色、绿色、蓝色像素(也未饱和)。

  • 计算左侧R、G、B的上百分位数(例如百分位数95)。

计算左侧R、G、B的上百分位数(比如百分位数95)。
我们假设(leftRup, leftGup, leftBup)表示左侧的白色。
我们假设(rightRup, rightGup, rightBup)代表右侧的白色。
MATLAB代码示例:

leftRup = prctile(leftR, 95);
    leftGup = prctile(leftG, 95);
    leftBup = prctile(leftB, 95);

    rightRup = prctile(rightR, 95);
    rightGup = prctile(rightG, 95);
    rightBup = prctile(rightB, 95);
  • 假设绿色像素保持未修改(假设仅比率是重要的)。

我们希望以如下方式校正左侧的比率:
leftRup / leftGup = rightRup / rightGup
leftBup / leftGup = rightBup / rightGup
计算左侧红色通道的比例因子。
计算左侧蓝色通道的比例因子。
leftRscale = (rightRup/rightGup) / (leftRup/leftGup)
leftBscale = (rightBup/rightGup) / (leftBup/leftGup)

  • 缩放左侧的红色和蓝色通道(使用遮罩)。
  • 将校正后的R、G、B通道连接到RGB图像中,并从线性RGB转换回sRGB(应用伽玛)

MATLAB代码示例(抱歉没有使用C++或Python):

I = imread('original_image.jpg');
Mask = imread('mask.jpg');

figure;imshow(I);title(I);  % Show the input for testing

I = im2double(I); % Convert I from uint8 in range [0, 255] to double in range [0, 1] (use double for improving the accuracy).
I = rgb2lin(I); % Convert from sRGB to Linear RGB space (inverse gamma).

% Fix the mask, for getting better results.
Mask = imbinarize(Mask); % Convert to binary image.
Mask = bwareaopen(Mask, 5000); % Remove small connected components - assumed to be noise.
Mask = imdilate(Mask, ones(21, 21)); % Dilate the mask
Mask = bwfill(Mask, 'holes'); % Fill holes in the mask

% Extract Red, Green and Blue color channels
R = I(:, :, 1);
G = I(:, :, 2);
B = I(:, :, 3);

% Mask of non-saturated pixels (assume pixels values above 250 are saturated, and should be excluded).
NoSatR = R < 250;
NoSatG = G < 250;
NoSatB = B < 250;

leftR = R(Mask & NoSatR); % Extract all red pixels in the left side that are also not saturated.
leftG = G(Mask & NoSatG);
leftB = B(Mask & NoSatB);

rightR = R(~Mask & NoSatR); % Extract all red pixels in the right side that are also not saturated.
rightG = G(~Mask & NoSatG);
rightB = B(~Mask & NoSatB);

% Assume RGB of white pixel in the left size is (leftRup, leftGup, leftBup)
leftRup = prctile(leftR, 95); % Compute upper percentile of R in the left side.
leftGup = prctile(leftG, 95); % Compute upper percentile of G in the left side.
leftBup = prctile(leftB, 95); % Compute upper percentile of B in the left side.

% Assume RGB of white pixel in the right size is (rightRup, rightGup, rightBup)
rightRup = prctile(rightR, 95); % Compute upper percentile of R in the left side.
rightGup = prctile(rightG, 95); % Compute upper percentile of G in the left side.
rightBup = prctile(rightB, 95); % Compute upper percentile of B in the left side.

% We want to correct the ratios of the left side in such way that:
% leftRup / leftGup = rightRup / rightGup
% leftBup / leftGup = rightBup / rightGup
% We also assume that the green pixels kept unmodified (assume that only the ratios are important)

leftRscale = (rightRup/rightGup) / (leftRup/leftGup); % Compute the scale factor of the red channel in the left side
leftBscale = (rightBup/rightGup) / (leftBup/leftGup); % Compute the scale factor of the blue channel in the left side

% Scale the red and blue channels of the left side.
R(Mask) = R(Mask) * leftRscale;
B(Mask) = B(Mask) * leftBscale;

% Join corrected R, G, B channels to into RGB image
J = cat(3, R, G, B);

J = lin2rgb(J); % Convert from Linear RGB to sRGB (apply gamma).
J = im2uint8(J); % Convert back from double to uint8.

figure;imshow(J);title(J); % Show the output for testing

imwrite(J, 'J.jpg'); % Save the output for testing

输出:

注意事项:
固定红/绿色和蓝/绿的比率是近似值。
有一种更精确的方法称为CAT -Chromatic Adaptation校正。

相关问题