#include<iostream>
#include<string.h>
#include<math.h>
#include<vector>
#include<opencv2/core/core.hpp>
#include<opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include<opencv2/highgui.hpp>
#include "opencv2/ml.hpp"
#include "opencv2/objdetect.hpp"
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2\imgproc\imgproc_c.h>
#include<opencv2\highgui\highgui.hpp>
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
void swap(int& x, int& y)
{
int temp;
temp = x;
x = y;
y = temp;
}
// 去噪匹配
int searchmedia(int *arr, int length)
{
int i, j;
for (i = 0; i < length - 1; i++)
for (j = 0; j < length - i - 1; j++)
{
if (arr[j] > arr[j + 1])
swap(arr[j], arr[j + 1]);
}
return arr[4];
}
// 中值滤波去噪处理
void MediaFilter(Mat& Saltimg, Mat& _dst)
{
Mat dst = Mat(Saltimg.size(), Saltimg.type());
int arr[9];
// channels()返回矩阵通道的数量。
if (dst.channels() == 3)
{
for (int i = 0; i < dst.rows; i++)
for (int j = 0; j < dst.cols; j++)
{
if (i - 1 > 0 && j - 1 > 0 && i < dst.rows - 1 && j < dst.cols - 1)
{
arr[0] = Saltimg.at<Vec3b>(i - 1, j - 1)[0];
arr[1] = Saltimg.at<Vec3b>(i - 1, j)[0];
arr[2] = Saltimg.at<Vec3b>(i - 1, j + 1)[0];
arr[3] = Saltimg.at<Vec3b>(i, j - 1)[0];
arr[4] = Saltimg.at<Vec3b>(i, j)[0];
arr[5] = Saltimg.at<Vec3b>(i, j + 1)[0];
arr[6] = Saltimg.at<Vec3b>(i + 1, j - 1)[0];
arr[7] = Saltimg.at<Vec3b>(i + 1, j)[0];
arr[8] = Saltimg.at<Vec3b>(i + 1, j + 1)[0];
dst.at<Vec3b>(i, j)[0] = searchmedia(arr, 9);
arr[0] = Saltimg.at<Vec3b>(i - 1, j - 1)[1];
arr[1] = Saltimg.at<Vec3b>(i - 1, j)[1];
arr[2] = Saltimg.at<Vec3b>(i - 1, j + 1)[1];
arr[3] = Saltimg.at<Vec3b>(i, j - 1)[1];
arr[4] = Saltimg.at<Vec3b>(i, j)[1];
arr[5] = Saltimg.at<Vec3b>(i, j + 1)[1];
arr[6] = Saltimg.at<Vec3b>(i + 1, j - 1)[1];
arr[7] = Saltimg.at<Vec3b>(i + 1, j)[1];
arr[8] = Saltimg.at<Vec3b>(i + 1, j + 1)[1];
dst.at<Vec3b>(i, j)[1] = searchmedia(arr, 9);
arr[0] = Saltimg.at<Vec3b>(i - 1, j - 1)[2];
arr[1] = Saltimg.at<Vec3b>(i - 1, j)[2];
arr[2] = Saltimg.at<Vec3b>(i - 1, j + 1)[2];
arr[3] = Saltimg.at<Vec3b>(i, j - 1)[2];
arr[4] = Saltimg.at<Vec3b>(i, j)[2];
arr[5] = Saltimg.at<Vec3b>(i, j + 1)[2];
arr[6] = Saltimg.at<Vec3b>(i + 1, j - 1)[2];
arr[7] = Saltimg.at<Vec3b>(i + 1, j)[2];
arr[8] = Saltimg.at<Vec3b>(i + 1, j + 1)[2];
dst.at<Vec3b>(i, j)[2] = searchmedia(arr, 9);
}
else
{
dst.at<Vec3b>(i, j)[0] = Saltimg.at<Vec3b>(i, j)[0];
dst.at<Vec3b>(i, j)[1] = Saltimg.at<Vec3b>(i, j)[1];
dst.at<Vec3b>(i, j)[2] = Saltimg.at<Vec3b>(i, j)[2];
}
}
}
else if (dst.channels() == 1)
{
for (int i = 0; i < dst.rows; i++)
for (int j = 0; j < dst.cols; j++)
{
if (i - 1 > 0 && j - 1 > 0 && i < dst.rows - 1 && j < dst.cols - 1)
{
arr[0] = Saltimg.at<uchar>(i - 1, j - 1);
arr[1] = Saltimg.at<uchar>(i - 1, j);
arr[2] = Saltimg.at<uchar>(i - 1, j + 1);
arr[3] = Saltimg.at<uchar>(i, j - 1);
arr[4] = Saltimg.at<uchar>(i, j);
arr[5] = Saltimg.at<uchar>(i, j + 1);
arr[6] = Saltimg.at<uchar>(i + 1, j - 1);
arr[7] = Saltimg.at<uchar>(i + 1, j);
arr[8] = Saltimg.at<uchar>(i + 1, j + 1);
dst.at<uchar>(i, j) = searchmedia(arr, 9);
}
else
{
dst.at<uchar>(i, j) = Saltimg.at<uchar>(i, j);
}
}
}
dst.copyTo(_dst);
}
int gray[256] = { 0 }; //记录每个灰度级别下的像素个数
double gray_prob[256] = { 0 }; //记录灰度分布密度
double gray_distribution[256] = { 0 }; //记录累计密度
int gray_equal[256] = { 0 }; //均衡化后的灰度值
int gray_sum = 0; //像素总数
Mat equalize_hist(Mat& input)
{
Mat output = input.clone();
gray_sum = input.cols * input.rows;
//统计每个灰度下的像素个数
for (int i = 0; i < input.rows; i++)
{
uchar* p = input.ptr<uchar>(i);
for (int j = 0; j < input.cols; j++)
{
int vaule = p[j];
gray[vaule]++;
}
}
//统计灰度频率
for (int i = 0; i < 256; i++)
{
gray_prob[i] = ((double)gray[i] / gray_sum);
}
//计算累计密度
gray_distribution[0] = gray_prob[0];
for (int i = 1; i < 256; i++)
{
gray_distribution[i] = gray_distribution[i - 1] + gray_prob[i];
}
//重新计算均衡化后的灰度值,四舍五入。参考公式:(N-1)*T+0.5
for (int i = 0; i < 256; i++)
{
gray_equal[i] = (uchar)(255 * gray_distribution[i] + 0.5);
}
//直方图均衡化,更新原图每个点的像素值
for (int i = 0; i < output.rows; i++)
{
uchar* p = output.ptr<uchar>(i);
for (int j = 0; j < output.cols; j++)
{
p[j] = gray_equal[p[j]];
}
}
return output;
}
// 画直方图
void drawHist(Mat& img)
{
//为计算直方图配置变量
//首先是需要计算的图像的通道,就是需要计算图像的哪个通道(bgr空间需要确定计算 b或g货r空间)
int channels = 0;
//然后是配置输出的结果存储的 空间 ,用MatND类型来存储结果
MatND dstHist;
//接下来是直方图的每一个维度的 柱条的数目(就是将数值分组,共有多少组)
int histSize[] = { 256 }; //如果这里写成int histSize = 256; 那么下面调用计算直方图的函数的时候,该变量需要写 &histSize
//最后是确定每个维度的取值范围,就是横坐标的总数
//首先得定义一个变量用来存储 单个维度的 数值的取值范围
float midRanges[] = { 0, 256 };
const float *ranges[] = { midRanges };
calcHist(&img, 1, &channels, Mat(), dstHist, 1, histSize, ranges, true, false);
//calcHist 函数调用结束后,dstHist变量中将储存了 直方图的信息 用dstHist的模版函数 at<Type>(i)得到第i个柱条的值
//at<Type>(i, j)得到第i个并且第j个柱条的值
//开始直观的显示直方图——绘制直方图
//首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像
Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);
//因为任何一个图像的某个像素的总个数,都有可能会有很多,会超出所定义的图像的尺寸,针对这种情况,先对个数进行范围的限制
//先用 minMaxLoc函数来得到计算直方图后的像素的最大个数
double g_dHistMaxValue;
minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);
//将像素的个数整合到 图像的最大范围内
//遍历直方图得到的数据
for (int i = 0; i < 256; i++)
{
int value = cvRound(dstHist.at<float>(i) * 256 * 0.9 / g_dHistMaxValue);
line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - value), Scalar(255, 255, 255));
}
namedWindow("直方图",WINDOW_AUTOSIZE);
imshow("直方图", drawImage);
}
int DetectThreshold(Mat *src)
{
uchar iThrehold;//阀值
try
{
int height = src->cols;
int width = src->rows;
int step = src->rows / sizeof(uchar);
uchar *data = src->data;
cout << src->cols << endl
<< src->rows<<endl;
int iDiffRec = 0;
int F[256] = { 0 }; //直方图数组
int iTotalGray = 0;//灰度值和
int iTotalPixel = 0;//像素数和
uchar bt;//某点的像素值
uchar iNewThrehold;//新阀值
uchar iMaxGrayValue = 0, iMinGrayValue = 255;//原图像中的最大灰度值和最小灰度值
uchar iMeanGrayValue1, iMeanGrayValue2;
//获取(i,j)的值,存于直方图数组F
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
bt = data[i*step + j];
if (bt < iMinGrayValue)
iMinGrayValue = bt;
if (bt > iMaxGrayValue)
iMaxGrayValue = bt;
F[bt]++;
}
}
iThrehold = 0;
iNewThrehold = (iMinGrayValue + iMaxGrayValue) / 2;//初始阀值
iDiffRec = iMaxGrayValue - iMinGrayValue;
for (int a = 0; (abs(iThrehold - iNewThrehold) > 0.5); a++)//迭代中止条件
{
iThrehold = iNewThrehold;
//小于当前阀值部分的平均灰度值
for (int i = iMinGrayValue; i < iThrehold; i++)
{
iTotalGray += F[i] * i;//F[]存储图像信息
iTotalPixel += F[i];
}
iMeanGrayValue1 = (uchar)(iTotalGray / iTotalPixel);
//大于当前阀值部分的平均灰度值
iTotalPixel = 0;
iTotalGray = 0;
for (int j = iThrehold + 1; j < iMaxGrayValue; j++)
{
iTotalGray += F[j] * j;//F[]存储图像信息
iTotalPixel += F[j];
}
iMeanGrayValue2 = (uchar)(iTotalGray / iTotalPixel);
iNewThrehold = (iMeanGrayValue2 + iMeanGrayValue1) / 2; //新阀值
iDiffRec = abs(iMeanGrayValue2 - iMeanGrayValue1);
}
}
catch (cv::Exception e)
{
}
return iThrehold;
}
//度数转换
double degreeTurn(double theta)
{
double finaldegree = theta / CV_PI * 180;
return finaldegree;
}
//逆时针旋转图像degree角度(原尺寸)
void rotateImage(Mat Img, Mat& rotateImg, double degree)
{
//旋转中心为图像中心
Point2f center;
center.x = float(Img.cols / 2.0);
center.y = float(Img.rows / 2.0);
int length = 0;
length = sqrt(Img.cols * Img.cols + Img.rows * Img.rows);
Mat matrix = getRotationMatrix2D(center, degree, 1);//仿射变换矩阵
warpAffine(Img, rotateImg, matrix, Size(length, length), 1, 0, Scalar(255, 255, 255));//原大小进行仿射变换
}
//通过霍夫变换计算角度
double CalcDegree(const Mat& srcImage)
{
Mat midImage;
Sobel(srcImage, midImage, -1, 0, 1, 5);
//通过霍夫变换检测直线
vector<Vec2f> lines;
HoughLines(midImage, lines, 1, CV_PI / 180, 300, 0, 0);//阈值越大,精度越高
//根据阈值由大到小设置了三个阈值,如果经过大量试验后,可以固定一个适合的阈值。
if (!lines.size())
{
HoughLines(midImage, lines, 1, CV_PI / 180, 200, 0, 0);
}
if (!lines.size())
{
HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);
}
float all_t = 0;
for (size_t i = 0; i < lines.size(); i++)
{
float theta = lines[i][1];//选择角度最小的角作为旋转角
//计算所有角度
all_t += theta;
}
float average = all_t / lines.size(); //对所有角度求平均
double degree = degreeTurn(average) - 90;
return degree;
}
int main()
{
// 存放所有路径名
vector<string> m_item;
//string m_pathname="D:\\Study\\temp\\image\\*.jpg";
string m_pathname = "image\\*.jpg";
glob(m_pathname, m_item);
/*
路径测试
vector<string>::iterator it;
for (it=m_item.begin();it!= m_item.end() ; it++)
{
cout << *it << endl;
}*/
// 处理每一个图片
for (int i = 0; i < m_item.size(); ++i)
{
Mat src = imread(m_item[i]);
if (src.empty())
{
cout << "加载图片 :" << m_item[i] << " 失败!" << endl;
continue;
}
Mat gray_dst, result_dst;
cvtColor(src, gray_dst, COLOR_BGR2GRAY);
// 去噪处理
MediaFilter(gray_dst, result_dst);
/*
去噪处理后 图片显示测试代码
*/
namedWindow("原图", WINDOW_NORMAL);
imshow("原图", src);
namedWindow("灰度图", WINDOW_NORMAL);
imshow("灰度图", gray_dst);
// 去噪处理
MediaFilter(gray_dst, result_dst);
namedWindow("中值滤波去噪后", WINDOW_NORMAL);
imshow("中值滤波去噪后", result_dst);
//cout << "处理图片 :" << m_item[i] << " 成功!" << endl;
// 灰度直方图
//int nRows = 600, nCols = 800;
//Mat g_dstImg(nRows, nCols, CV_8UC1, Scalar::all(0)); // 新建画布
//namedWindow("g_dstImg", WINDOW_AUTOSIZE);
//imshow("g_dstImg", g_dstImg);
//Mat histImg = equalize_hist(result_dst);
// namedWindow("均值化图", WINDOW_NORMAL);
//imshow("均值化图", histImg);
// drawHist(result_dst);
drawHist(result_dst);
// adaptiveThreshold(result_dst, temp, 255,ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY,21,10);
//namedWindow("原图", WINDOW_NORMAL);
//imshow("原图", histImg);
Mat *decect=new Mat(result_dst);
int dec=DetectThreshold(decect);
cout << dec << endl;
Mat binaryImg;
threshold(result_dst, binaryImg, dec, 255, CV_THRESH_BINARY);
namedWindow("二值图", WINDOW_NORMAL);
imshow("二值图", binaryImg);
//Mat angleImg;
//angleCount(result_dst,angleImg);
//namedWindow("角度图", WINDOW_NORMAL);
//imshow("角度图", angleImg);
// 输出二值图片
//string strnn;
//strnn += ".\\new\\";
//strnn += m_item[i];
//strnn += +".jpg";
//cout << strnn << endl;
//imwrite(strnn, binaryImg);
waitKey(0);
}
waitKey(0);
return 0;
}