# NO.8 C + + histogram & convolution

Zero erosion

### histogram

• #### Histogram drawing

• The histogram drawing we use in python has been drawn internally, but the histogram on C + + needs to draw a straight line by ourselves. We can only get the corresponding data on the api.
```#include  <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(){
Mat gray;
cvtColor(src,gray,COLOR_RGB2GRAY);
imshow("src",src);

Mat hist; // dst
int channels=0; //
int histSize=256;
float range[]={0,255};
const float* h_rang = range;

// Collect histogram data, source data, quantity, mask, channel index, data, latitude, range,
calcHist(&gray,1, &channels,Mat(),hist,1,&histSize,&h_rang);

/** Draw histogram**/
Mat dst = Mat::zeros(Size(1200,500),CV_8UC3);
// Data normalization processing (distributing data to 0-400)
Mat norm;
normalize(hist,norm,0,400,NORM_MINMAX);
// Draw data
for (int a=0;a<256;++a){
int xOffset = a*4 + 100;
float y = norm.at<float>(a);
line(dst,Point(xOffset,500),Point(xOffset, static_cast<int>(500 - y)),Scalar(255,255,255,2),2);
}
imshow("dst",dst);

waitKey(0);
return 0;
}
```

• #### Histogram equalization

• Calculation method of Equalization: calculate the value of gray image, then convert it to the frequency of occurrence, calculate the cumulative probability, and equalize according to the cumulative probability. Equalization is to make the image softer and approximate some prominent color values to the overall color.
```// main
#include  <iostream>
#include <opencv2/opencv.hpp>
#include "equalization.h"

int main(){
// Histogram equalization
histEqualization("../resource/ashin.jpg","after");
return 0;
}

// Function cpp
//
// Created by zero erosion on November 15, 2020
//

#include "equalization.h"

void histEqualization(string path, string title) {
Mat gray;
cvtColor(src, gray, COLOR_RGB2GRAY);

// Histogram value of gray scale
int channels = 0;
const int size = 256;
float range[] = {0, 255};
const float *ranges = range;
Mat hist;
calcHist(&gray, 1, &channels, Mat(), hist, 1, &size, &ranges);

// Calculate the probability
Mat radio = hist / (gray.rows * gray.cols);

// Calculate cumulative probability
Mat calculator(256,1,CV_32FC1);
float s = 0;
for (int i = 0; i < 256; i++) {
s+=r;
calculator.at<float>(i)=s;
}
imshow("before", gray);

// Equalization according to cumulative probability
for(int m = 0;m<gray.rows;m++){
for (int n = 0; n < gray.cols; ++n) {
int color  =  gray.at<uint8_t>(m,n);
// Find the scale corresponding to the color
float per = calculator.at<float>(color);
// Equalization (255 * cumulative color proportion)
gray.at<uint8_t>(m,n) = static_cast<uint8_t>(255 * per);
}
}

imshow(title, gray);
waitKey();
}
```

• ### Histogram matching

• The main process of histogram is to get the minimum difference between the two images by calculating the cumulative probability of the original image and the target image, and then map. This is histogram matching. It's more like two images with the smallest difference in hue fusion.
```#include "match.h
int main(){
// Original image, mapped image data
histMatch("../resource/collapse.jpg","../resource/ashin.jpg");
return 0;
}
// match.cpp
//
// Created by zero erosion on November 15, 2020
//

#include "match.h"

void getEqualHist(Mat *mat, Mat *calculator);
void getMatchColor(Mat *srcSum, Mat *referSum,Mat *color);
void oneChannelMatch(Mat* srcChannel,Mat* referChannel);

void histMatch(string src_path, string refer_path) {
// Get the original map and the map to be mapped

imshow("srcGray", src);
imshow("referGray", refer);
// Channel cutting
vector<Mat> chsSrc;
vector<Mat> chsRefer;
split(src, chsSrc);
split(refer, chsRefer);

// Gray matching
//Mat graySrc;
//cvtColor(src,graySrc,COLOR_RGB2GRAY);
//Mat grayRefer;
//cvtColor(refer,grayRefer,COLOR_RGB2GRAY);
//oneChannelMatch(&graySrc,&grayRefer);

// Single channel matching
oneChannelMatch(&chsSrc[0],&chsRefer[0]);
oneChannelMatch(&chsSrc[1],&chsRefer[1]);
oneChannelMatch(&chsSrc[2],&chsRefer[2]);

// Multi-channel fusion
merge(chsSrc,src);
imshow("result", src);
waitKey();

}

/**
* Color value matching of single channel
* @param srcChannel
* @param referChannel
*/
void oneChannelMatch(Mat* srcChannel,Mat* referChannel){

Mat srcCalculator(256,1,CV_32FC1);
getEqualHist(srcChannel,&srcCalculator);
Mat referCalculator(256,1,CV_32FC1);
getEqualHist(referChannel,&referCalculator);
Mat color(256,1,CV_8UC1);
getMatchColor(&srcCalculator,&referCalculator,&color);

// Get the minimum difference color
for(int row =0 ; row< srcChannel->rows;++row){
for (int col = 0; col < srcChannel->cols; ++col) {
// The color value obtained from the original image
int colorValue = srcChannel->at<uint8_t>(row,col);
//cout<< "colorValue="<<colorValue<<endl;
// Get the color value of the corresponding target
uchar value = color.at<uchar>(colorValue);

// Update image information
srcChannel->at<uint8_t>(row,col)=value;

}
}

}

/**
* Get cumulative probability
* @param mat
* @param calculator
* @return
*/

void getEqualHist(Mat *mat, Mat *calculator) {
// Histogram value of gray scale
int channels = 0;
const int size = 256;
float range[] = {0, 255};
const float *ranges = range;
Mat hist;
calcHist(mat, 1, &channels, Mat(), hist, 1, &size, &ranges);

// Calculate the probability
Mat radio = hist / (mat->rows * mat->cols);

// Calculate cumulative probability
//*calculator = Mat::zeros(256, 1, CV_32FC1);

float s = 0;
for (int i = 0; i < 256; i++) {
s += r;
calculator->at<float>(i) = s;
}

}

/**
* Obtain the cumulative probability difference between the original image and the target image
* @param srcSum
* @param referSum
* @param color
*/

void getMatchColor(Mat *srcSum, Mat *referSum,Mat *color) {

for (int i = 0; i < 256; i++) {
float aimValue = 10;
int index = 0;
cout<<"=========="<<endl;
for (int j = 0; j < 256; ++j) {
// Calculate the minimum difference of cumulative probability
if(diffValue < aimValue){
aimValue = diffValue;
index = j;
color->at<uint8_t>(i)= static_cast<uint8_t>(index);
}

}

}
}
```
• As shown in the figure below, the original image in the upper left corner blends the hue in the upper right corner into the image, and finally generates the hue in the lower left corner. Gray matching

• Color matching

[external chain picture transfer failed, the source station may

### convolution

• #### convolution

• Convolution is mainly an operation between the pixels of the image and the surrounding pixels, which can make the image smaller color difference (blur) or improve the color value (sharpen). See the corresponding part of android for the specific principle.
```void showFilter(string path) {
Mat dst;
// Build kernel
Mat kernel = (Mat_<char>(3, 3) <<  -1, -1, -1,
-1, -1, 9, -1,
-1, -1, -1);
filter2D(src, dst, -1,kernel);

//You can enlarge the picture
namedWindow("src",WINDOW_NORMAL);
imshow("src",src);
imshow("dst",dst);
waitKey();

}
```

• laplacian (laplacian operator). The information presented by laplacian algorithm is more delicate than canny. It directly retains only the edge information of the image, and it is obvious that laplacian will retain some details inside the image.
```void showLaplacian(string path){
Mat dst ;
Laplacian(src,dst,CV_16S);
// Since the calculation may lead to overflow, some algorithms need to be used for acceleration (because the default is 8-bit uint8, while CV_16S is 16 bits, so it needs to be accelerated, which can also make the image clearer.)
convertScaleAbs(dst,dst);

imshow("src",src);
imshow("dst",dst);
waitKey();

}
```

• Sobel & ScHARR operator
```void showSobel(string path){
Mat dst ;
// Sobel(src,dst,-1,1,0);
// Since the calculation may lead to overflow, some algorithms need to be used to speed up
// x direction
Sobel(src,dst,CV_16S,1,0);
convertScaleAbs(dst,dst);
// y direction
Mat dstY;
Sobel(src,dstY,CV_16S,0,1);
convertScaleAbs(dstY,dstY);

Mat dst;

imshow("src",src);
imshow("dst",dst);
waitKey();
}
```

```void showSobel(string path){