Hello there,
I try to implement subtraction of two images. I am sure there are too many people who are ready to shot me with their "Why don't you just use cv::subtract or simply cv::Mat Result = Image1 - Image2;" gun. Jokes aside, the reason is that I try to implement my own version to use it as a function which is going to run on separate threads. When I used
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <new>
#include <chrono>
#include <omp.h>
void rgbToHsv(cv::Mat* inputImage, cv::Mat* outputImage);
void subtractImage(cv::Mat* inputImage, cv::Mat* outputImage, cv::Mat* imageMask);
int main(int argc, char const *argv[])
{
cv::Mat inputImage = imread("lena.png", cv::IMREAD_UNCHANGED); //Input image
//Converting image from RGB to HSV colorspace
cv::Mat inputImageHsv = inputImage.clone();
rgbToHsv(&inputImage, &inputImageHsv);
//Splitting V channel for later use
cv::Mat inputImageHsvChannels[3];
cv::split(inputImageHsv, inputImageHsvChannels);
cv::Mat inputImageH = inputImageHsvChannels[0];
cv::Mat inputImageS = inputImageHsvChannels[1];
cv::Mat inputImageV = inputImageHsvChannels[2];
cv::Mat blurredImage = inputImageV.clone();
cv::Mat imageMask = inputImageV.clone();
cv::Mat imageMask2 = inputImageV.clone();
cv::Mat imageMask3 = inputImageV.clone();
cv::GaussianBlur(inputImageV, blurredImage, cv::Size(5,5), 0, 0);
cv::subtract(inputImageV,blurredImage, imageMask);
imageMask2 = inputImageV - blurredImage;
subtractImage(&inputImageV, &blurredImage, &imageMask3);
cv::imshow("Subtracted Image1 OPENCV", imageMask);
cv::imshow("Subtracted Image2 OPENCV", imageMask2);
cv::imshow("Subtracted Image3 MY FUNC", imageMask3);
cv::waitKey();
return 0;
}
void subtractImage(cv::Mat* inputImage1, cv::Mat* inputImage2, cv::Mat* outputImage)
{
for(int i = 0; i < inputImage1->rows; ++i)
{
for(int j = 0; j < inputImage1->cols; ++j)
{
int iVal = inputImage1->at<uchar>(i,j) - inputImage2->at<uchar>(i,j);
if(iVal < 0)
outputImage->at<uchar>(i,j) = 0;
outputImage->at<uchar>(i,j) = iVal;
}
}
}
void rgbToHsv(cv::Mat* inputImage, cv::Mat* outputImage)
{
double redSc = 0, greenSc = 0, blueSc = 0; //Scaled R, G, B values of current pixel
double h = 0, s = 0, v = 0; //R, G, B values of current pixel
double cmin = 0, cmax = 0; //Min and max dummy variables
double delta = 0; //Difference between min and max
int channels = inputImage->channels();
int nRows = inputImage->rows;
int nCols = inputImage->cols*channels;
if (inputImage->isContinuous())
{
nCols *= nRows;
nRows = 1;
}
uchar* p;
uchar* q;
for(int i = 0; i < nRows; ++i){
p = inputImage->ptr<uchar>(i);
q = outputImage->ptr<uchar>(i);
for(int j = 0; j < nCols; j+=3){
redSc = p[j+2] / 255.;
greenSc = p[j+1] / 255.;
blueSc = p[j] / 255.;
cmin = std::min(std::min(redSc, greenSc), blueSc);
cmax = std::max(std::max(redSc, greenSc), blueSc);
delta = cmax - cmin;
if(!delta){
h = 0.;
s = 0.;
v = cmax * 255.;
}
else{
if(cmax == redSc)
h = 60. * ((greenSc - blueSc)/delta);
if(cmax == greenSc)
h = 120 + (60. * (((blueSc - redSc)/delta)));
if(cmax == blueSc)
h = 240 + (60. * (((redSc - greenSc)/delta)));
if(h < 0)
h += 360;
h = (h/2);
v = cmax* 255.;
s = ((cmax==0)?0:((delta/cmax)*255.));
q[j+2] = v; //Red
q[j+1] = s; //Green
q[j] = h; //Blue
}
}
}
}
Here are the results.