1.首先构造像素的频率直方图
2. 寻找直方图中的两个最大的波峰
3. 寻找这两个波峰之间的最小的波谷
4.波谷的index(像素值)为 K 值(阈值)
#include "JpegDecoder.h"#include#include #include using namespace JpegCodec;static cv::Mat ConvertToMat(Matrix &mat){ int channel = CV_8UC3; if (mat.channal == 1) channel = CV_8UC1; cv::Mat img(mat.rows, mat.cols, channel); // create a new matrix for (int i = 0; i < mat.rows * mat.cols * mat.channal; i++) { img.data[i] = mat.data[i]; } return img;}typedef struct{ int index; int freq; // frequence}Point;void Binary(Matrix &mat){ Point peaks[256]; // 波峰 int histogram[256]; //直方图 // 构造直方图 for (int i = 0; i < 255; i++) histogram[i] = 0; int cnt = mat.rows * mat.cols * mat.channal; for (int i = 0; i < cnt; i++) { histogram[mat.data[i]] ++; } // 统计波峰 int size = 0; for (int i = 1; i < 254; i++) { if (histogram[i] > histogram[i + 1] && histogram[i] < histogram[i - 1]) { peaks[size].index = i; peaks[size].freq = histogram[i]; size++; } } // 寻找最大的两个波峰 Point max = peaks[0], snd = peaks[0]; for (int i = 0; i < size; i++) { if (peaks[i].freq > max.freq) { snd = max; max = peaks[i]; } else if (peaks[i].freq > snd.freq) { snd = peaks[i]; } } // 寻找波谷 int i = (max.index > snd.index ? snd.index : max.index); size = (max.index > snd.index ? max.index : snd.index); Point K = max; for (; i < size; i++) { if (histogram[i] < K.freq) { K.freq = histogram[i]; K.index = i; } } //二值化 for (i = 0; i < cnt; i++) { if (mat.data[i] < K.index) mat.data[i] = 0; else mat.data[i] = 255; }}void ShowImage(Matrix &mat){ cv::Mat img = ConvertToMat(mat); cv::imshow("Bitmap", img);}void Gray(Matrix &dst, Matrix &src){ dst.Create(src.rows, src.cols, 1); for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { int idx = (i * src.rows + j) * 3; dst.data[idx / 3] = (src.data[idx] + src.data[idx + 1] + src.data[idx + 2]) / 3; } }}int main(int argc, char *arrv[]){ JpegDecoder decoder("01.jpg"); Matrix mat, dst; decoder.Decoder(mat); Gray(dst, mat); Binary(dst); ShowImage(dst); cvWaitKey(0); return 0;}
JpegCodec :
运行示例