jashliao 用 VC++ 實現 fanfuhan OpenCV 教學005 ~ opencv-005-像素(pixel)計算操作 [圖片合成(加/減/乘/除)]
jashliao 用 VC++ 實現 fanfuhan OpenCV 教學005 ~ opencv-005-像素(pixel)計算操作 [圖片合成(加/減/乘/除)]
資料來源: https://fanfuhan.github.io/
https://fanfuhan.github.io/2019/03/23/opencv-005/
GITHUB:https://github.com/jash-git/fanfuhan_ML_OpenCV
https://github.com/jash-git/jashliao-implements-FANFUHAN-OPENCV-with-VC
★前言:

★主題:
OPENCV提供等大且格式相同的兩張圖片進行四則運算的對應函數。
四則運算相關函數如下所列:
圖像相加: add(src1, src2, add_result);
圖像戴權種值相加(透明效果):addWeighted(src1, 0.5, src2, (1.0 – 0.5), 0.0, add_weight_result);
圖像相減: subtract(src1, src2, sub_result);
圖像相乘: multiply(src1, src2, mul_result);
圖像相除: divide(src1, src2, div_result);
★C++
// VC_FANFUHAN_OPENCV005.cpp : 定義主控台應用程式的進入點。
//
/*
// Debug | x32
通用屬性
| C/C++
| | 一般
| | 其他 Include 目錄 -> C:\opencv\build\include
|
| 連結器
| |一一般
| | 其他程式庫目錄 -> C:\opencv\build\x64\vc15\lib
|
| |一輸入
| | 其他相依性 -> opencv_world411d.lib;%(AdditionalDependencies)
// Releas | x64
組態屬性
| C/C++
| | 一般
| | 其他 Include 目錄 -> C:\opencv\build\include
|
| 連結器
| |一般
| | 其他程式庫目錄 -> C:\opencv\build\x64\vc15\lib
|
| |一輸入
| | 其他相依性 -> opencv_world411.lib;%(AdditionalDependencies)
*/
#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
void pause()
{
printf("Press Enter key to continue...");
fgetc(stdin);
}
int main()
{
Mat src1 = imread("../../images/LinuxLogo.jpg");
Mat src2 = imread("../../images/WindowsLogo.jpg");
//Mat image = imread("../../../images/l_hires.jpg", IMREAD_GRAYSCALE);//執行檔 測試路徑
if (src1.empty() || src2.empty()) {
cout << "could not load image..." << endl;
pause();
return -1;
}
else
{
imshow("input1", src1);
imshow("input2", src2);
// 加法
Mat add_result = Mat::zeros(src1.size(), src1.type());
add(src1, src2, add_result);
imshow("add_result", add_result);
// 带权重的加法,一般推荐使用这个 浮水印 透明感
Mat add_weight_result = Mat::zeros(src1.size(), src1.type());
addWeighted(src1, 0.5, src2, (1.0 - 0.5), 0.0, add_weight_result);
imshow("add_weight_result", add_weight_result);
// 减法
Mat sub_result = Mat::zeros(src1.size(), src1.type());
subtract(src1, src2, sub_result);
imshow("sub_result", sub_result);
// 乘法
Mat mul_result = Mat::zeros(src1.size(), src1.type());
multiply(src1, src2, mul_result);
imshow("mul_result", mul_result);
// 除法
Mat div_result = Mat::zeros(src1.size(), src1.type());
divide(src1, src2, div_result);
imshow("div_result", div_result);
// 自己实现加法操作
int b1 = 0, g1 = 0, r1 = 0;
int b2 = 0, g2 = 0, r2 = 0;
Mat my_add_result = Mat::zeros(src1.size(), src1.type());
for (int row = 0; row < src1.rows; ++row) {
for (int col = 0; col < src1.cols; ++col) {
b1 = src1.at<Vec3b>(row, col)[0];
g1 = src1.at<Vec3b>(row, col)[1];
r1 = src1.at<Vec3b>(row, col)[2];
b2 = src2.at<Vec3b>(row, col)[0];
g2 = src2.at<Vec3b>(row, col)[1];
r2 = src2.at<Vec3b>(row, col)[2];
// b1:0~255,b2:0~255, b1+b2可能大于255,所以需要转换,通过saturate_cast<uchar>()
my_add_result.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b1 + b2);
my_add_result.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g1 + g2);
my_add_result.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r1 + r2);
}
}
imshow("my_add_result", my_add_result);
imwrite("add_result.jpg", add_result);
imwrite("add_weight_result.jpg", add_weight_result);
imwrite("sub_result.jpg", sub_result);
imwrite("div_result.jpg", div_result);
waitKey(0);
}
return 0;
}
★Python
import cv2 as cv
import numpy as np
src1 = cv.imread("../images/opencv_images/LinuxLogo.jpg");
src2 = cv.imread("../images/opencv_images/WindowsLogo.jpg");
cv.imshow("input1", src1)
cv.imshow("input2", src2)
h, w, ch = src1.shape
print("h , w, ch", h, w, ch)
add_result = np.zeros(src1.shape, src1.dtype);
cv.add(src1, src2, add_result);
cv.imshow("add_result", add_result);
sub_result = np.zeros(src1.shape, src1.dtype);
cv.subtract(src1, src2, sub_result);
cv.imshow("sub_result", sub_result);
mul_result = np.zeros(src1.shape, src1.dtype);
cv.multiply(src1, src2, mul_result);
cv.imshow("mul_result", mul_result);
div_result = np.zeros(src1.shape, src1.dtype);
cv.divide(src1, src2, div_result);
cv.imshow("div_result", div_result);
cv.waitKey(0)
cv.destroyAllWindows()
★結果圖:

★延伸說明/重點回顧:
想要使用OPENCV提供的四則運算函數前提條件必須是在兩張被運算圖像的類型類型、通道數據、大小都必須相同情況下。
由於上述的使用條件,當我們要自己撰寫類似功能時,記得使用saturate_cast <T> (value) 進行類型轉換,確保運算結果介於0~255,藉此預防運算錯誤。
PS.影像(圖像)處理中: 黑色(0,0,0) 白色(255,255,255)