计算机视觉课程(Win10+OpenCV+Qt)
说明
为记录研一计算机视觉课程作业代码而写,工程名为week1_qt,算是图像处理的入门,代码里可能有一些错误(原理或代码编写)
week1_qt.h
#ifndef WEEK1_QT_H
#define WEEK1_QT_H
#include <QtWidgets/QMainWindow>
#include "ui_week1_qt.h"
#include <opencv2/opencv.hpp>
#include <QImage>
#include <QPixmap>
#include <QFileDialog>
#include <QMessageBox>
#include <QScreen>
#include <QGuiApplication>
#include<QGraphicsScene>
#include<QGraphicsView> //graphicsview类
#include<opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp> //opencv申明
#include <qfiledialog.h> //getopenfilename 类申明
#include <qlabel.h>
//QT_CHARTS_USE_NAMESPACE
class week1_qt : public QMainWindow
{
Q_OBJECT
public:
week1_qt(QWidget *parent = 0);
~week1_qt();
//自定义变量
cv::Mat src;
private:
Ui::week1_qtClass ui;
//自定义变量
cv::Mat image;
QLabel *label = new QLabel;
//信号函数
signals:
//槽函数
private slots:
//第一次作业
void pushButton_1_clicked();
void pushButton_2_clicked();
void pushButton_3_clicked();
void pushButton_4_clicked();
void pushButton_5_clicked();
//第二次作业
//1、去噪处理
//添加椒盐噪声
cv::Mat addSaltNoise();
//添加高斯噪声
cv::Mat addGaussianNoise();
//均值滤波
void my_MeanBlur();
//最大最小值滤波
void my_MaxMinBlur();
//中值滤波
void my_MedianBlur();
//2、阈值分割
void my_threshold();//可变阈值
void fengemianji();
//3、拉伸变换
//分段线性拉伸
void dividedLinearStrength();
//直方图拉伸
void zhifangtulashen();
//4、区域生长法
void RegionGrow();
//第三次作业
//1、边缘检测
//sobel算子
void my_sobel();
//canny算子
void my_prewitt();
//laplace算子
void my_roberts();
//2、边界提取
void my_boder();
//3、骨架提取
void gujiatiqu();
//第四次作业
//1、腐蚀膨胀
void fushipengzhang();
//2、直线检测
void line_detect();
//3、应用
void lvbo();
//第五次作业
//1、2、边界线链码及周长面积计算
void lianma();
//3、共生矩阵及特征
void gongsheng();
};
#endif // WEEK1_QT_H
main.cpp
#include "week1_qt.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
week1_qt w;
w.show();
return a.exec();
}
week1_qt.cpp
#include "week1_qt.h"
#include <QMainWindow>
#include <QtGui>
#include <QtWidgets>
#include<stack>
//#pragma execution_character_set("utf-8") // 解决汉字乱码问题,注意!!!
using namespace std;
using namespace cv;
//区域生长法
static Point connects[8] = { Point(-1, -1), Point(0, -1), Point(1, -1), Point(1, 0), Point(1, 1), Point(0, 1), Point(-1, 1), Point(-1, 0) };
Mat src_threshold;
Mat dst_threshold;
int thresholdValue = 100;
int w = 0;
int b = 0;
//主函数
week1_qt::week1_qt(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
week1_qt::~week1_qt()
{
}
//第一次作业
//普通函数
//彩色图像灰度化处理(采用加权法)
Mat RGB2GRAY(Mat src)
{
if (src.channels() == 1)
{
return src;
}
else if (src.channels() == 3 || src.channels() == 4)//第四通道表示透明度
{
//参数及初始化
Mat dst(src.rows, src.cols, CV_8UC1, Scalar(255));
double B, G, R;
B = 0.114;
G = 0.587;
R = 0.299;
int b_val, g_val, r_val;
//赋值
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
b_val = src.at<Vec3b>(i, j)[0];
g_val = src.at<Vec3b>(i, j)[1];
r_val = src.at<Vec3b>(i, j)[2];
dst.at<uchar>(i, j) = saturate_cast<uchar>(B*b_val + G*g_val + R*r_val);
}
}
return dst;
}
else
{
throw "error";
}
//cvtColor(src, dst, COLOR_BGR2GRAY, 0);
}
//灰度直方图(灰度图,彩图)
Mat Histogram(Mat src)
{
//灰度图
if (src.channels() == 1)
{
//参数准备
Mat dstHist;
int channels = 0;
int dims = 1;
int Num = 256;
int size[] = { Num };
float hranges[] = { 0,255 };
const float *ranges[] = { hranges };
//计算图像直方图
calcHist(&src, 1, &channels, Mat(), dstHist, dims, size, ranges);
int scale = 1;
Mat dst(Num * scale, Num, CV_8U, Scalar(0));
//获取最大值和最小值
double minValue = 0;
double maxValue = 0;
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);
//绘制出直方图
int hpt = saturate_cast<int>(0.9 * Num);
for (int i = 0; i < Num; i++)
{
float binValue = dstHist.at<float>(i);
int realValue = saturate_cast<int>(binValue * hpt / maxValue);
rectangle(dst, Point(i * scale, Num - 1), Point((i + 1)*scale - 1, Num - realValue), Scalar(255));
}
return dst;
}
else if (src.channels() == 3 || src.channels() == 4)
{
//参数准备
int bins = 256;
int hist_size[] = { bins };
float range[] = { 0, 256 };
const float* ranges[] = { range };
Mat redHist, grayHist, blueHist;
//直方图计算(红色部分)
int channels_r[] = { 0 };
calcHist(&src, 1, channels_r, Mat(), redHist, 1, hist_size, ranges);
//直方图计算(绿色部分)
int channels_g[] = { 1 };
calcHist(&src, 1, channels_g, Mat(), grayHist, 1, hist_size, ranges);
//直方图计算(蓝色部分)
int channels_b[] = { 2 };
calcHist(&src, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges);
//绘制三色直方图
//1、参数准备
double maxValue_red, maxValue_green, maxValue_blue;
minMaxLoc(redHist, 0, &maxValue_red, 0, 0);
minMaxLoc(grayHist, 0, &maxValue_green, 0, 0);
minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);
int scale = 1;
int histHeight = 256;
Mat dst = Mat::zeros(histHeight, bins * 3, CV_8UC3);
//2、正式绘制
for (int i = 0; i<bins; i++)
{
//参数准备
float binValue_red = redHist.at<float>(i);
float binValue_green = grayHist.at<float>(i);
float binValue_blue = blueHist.at<float>(i);
int intensity_red = cvRound(binValue_red*histHeight / maxValue_red); //要绘制的高度
int intensity_green = cvRound(binValue_green*histHeight / maxValue_green); //要绘制的高度
int intensity_blue = cvRound(binValue_blue*histHeight / maxValue_blue); //要绘制的高度 //绘制红色分量的直方图
rectangle(dst, Point(i*scale, histHeight - 1), Point((i + 1)*scale - 1, histHeight - intensity_red), Scalar(255, 0, 0));
//绘制绿色分量的直方图
rectangle(dst, Point((i + bins)*scale, histHeight - 1), Point((i + bins + 1)*scale - 1, histHeight - intensity_green), Scalar(0, 255, 0));
//绘制蓝色分量的直方图
rectangle(dst, Point((i + bins * 2)*scale, histHeight - 1), Point((i + bins * 2 + 1)*scale - 1, histHeight - intensity_blue), Scalar(0, 0, 255));
}
return dst;
}
else
{
throw "error";
}
}
//灰度图像的伪彩图像
Mat GRAY2RGB(Mat src)
{
if (src.channels() == 1)
{
//参数初始化
Mat dst(src.rows, src.cols, CV_8UC3, Scalar(0, 0, 0));
uchar r_val, g_val, b_val;
uchar gray_val;
//色彩转换
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
gray_val = src.at<uchar>(i, j);
//计算RGB通道像素值
if ((gray_val >= 0) && (gray_val <= 63))
{
r_val = 0;
g_val = saturate_cast<uchar>(254 - 4 * gray_val);
b_val = 255;
}
else if ((gray_val >= 64) && (gray_val <= 127))
{
r_val = 0;
g_val = saturate_cast<uchar>(4 * gray_val - 254);
b_val = saturate_cast<uchar>(510 - 4 * gray_val);
}
else if ((gray_val >= 128) && (gray_val <= 191))
{
r_val = saturate_cast<uchar>(4 * gray_val - 510);
g_val = 255;
b_val = 0;
}
else if ((gray_val >= 192) && (gray_val <= 255))
{
r_val = 255;
g_val = saturate_cast<uchar>(1022 - 4 * gray_val);
b_val = 0;
}
else
{
throw "red error";
}
//赋值
dst.at<Vec3b>(i, j)[2] = r_val;
dst.at<Vec3b>(i, j)[1] = g_val;
dst.at<Vec3b>(i, j)[0] = b_val;
}
}
return dst;
}
else if (src.channels() == 3 || src.channels() == 4)
{
return src;
}
else
{
throw "error";
}
}
//信号与槽函数
//槽函数
//读入图片
void week1_qt::pushButton_1_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("File Dialog"), "E:", tr("pic file(* png * jpg * bmp)"));
//判断是否有选择文件
if ("" == fileName) return;
//读取文件,并把QString类型转化为string
src = imread(string((const char *)fileName.toLocal8Bit()));
//显示图片
imshow("原图", src);
waitKey(0);
}
//灰度图
void week1_qt::pushButton_2_clicked()
{
Mat dst1 = RGB2GRAY(src);
imshow("灰度图", dst1);
}
//直方图
void week1_qt::pushButton_3_clicked()
{
Mat dst2 = Histogram(src);
imshow("彩色直方图", dst2);
Mat dst3 = Histogram(RGB2GRAY(src));
imshow("灰度直方图", dst3);
waitKey(0);
}
//伪彩图
void week1_qt::pushButton_4_clicked()
{
Mat dst4 = GRAY2RGB(RGB2GRAY(src));
imshow("伪彩图", dst4);
}
void week1_qt::pushButton_5_clicked()
{
Mat dst1 = RGB2GRAY(src);
Mat dst2 = Histogram(src);
Mat dst3 = Histogram(RGB2GRAY(src));
Mat dst4 = GRAY2RGB(RGB2GRAY(src));
imwrite("原图.jpg", src);
imwrite("灰度图.jpg", dst1);
imwrite("彩图直方图.jpg", dst2);
imwrite("灰度直方图.jpg", dst3);
imwrite("灰度伪彩图.jpg", dst4);
}
//第二次作业
//1、图像去噪
//添加椒盐噪声
Mat week1_qt::addSaltNoise()
{
Mat src = imread("E:/opencv project/homework/week1/data/2.jpg");
imshow("滤波原图", src);
int n = 1500;//n为添加多少个噪声点
Mat dst = src.clone();
for (int k = 0; k < n; k++)
{
//随机取值行列
int i = rand() % dst.rows;
int j = rand() % dst.cols;
//图像通道判定
if (dst.channels() == 1)
{
dst.at<uchar>(i, j) = 255; //盐噪声
}
else
{
dst.at<Vec3b>(i, j)[0] = 255;
dst.at<Vec3b>(i, j)[1] = 255;
dst.at<Vec3b>(i, j)[2] = 255;
}
}
for (int k = 0; k < n; k++)
{
//随机取值行列
int i = rand() % dst.rows;
int j = rand() % dst.cols;
//图像通道判定
if (dst.channels() == 1)
{
dst.at<uchar>(i, j) = 0; //椒噪声
}
else
{
dst.at<Vec3b>(i, j)[0] = 0;
dst.at<Vec3b>(i, j)[1] = 0;
dst.at<Vec3b>(i, j)[2] = 0;
}
}
imshow("椒盐噪声图", dst);
return dst;
}
//添加高斯噪声
//生成高斯噪声
double generateGaussianNoise(double m, double sigma)//m为均值,sigma为方差
{
//定义小值
const double epsilon = numeric_limits<double>::min();//返回的是编译器定义的最小的双精度浮点数
static double z0, z1;
static bool flag = false;
flag = !flag;
//flag为假,构造高斯随机变量X
if (!flag)
return z1 * sigma + m;
double u1, u2;
//构造随机变量
do
{
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
} while (u1 <= epsilon);
//flag为真,构造高斯随机变量
z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI*u2);
z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI*u2);
return z0 * sigma + m;
}
//为图像添加高斯噪声
Mat week1_qt::addGaussianNoise()
{
double generateGaussianNoise(double m, double sigma);
Mat src = imread("E:/opencv project/homework/week1/data/2.jpg");
double m = 0;
double sigma = 8;
Mat dst = src.clone();
int channels = dst.channels();
int rowsNumber = dst.rows;
int colsNumber = dst.cols * channels;
//推断图像的连续性
if (dst.isContinuous())
{
colsNumber *= rowsNumber;
rowsNumber = 1;
}
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
//加入高斯噪声
int val = dst.ptr<uchar>(i)[j] + generateGaussianNoise(m, sigma);
if (val < 0)
val = 0;
if (val>255)
val = 255;
dst.ptr<uchar>(i)[j] = (uchar)val;
}
}
imshow("高斯噪声", dst);
return dst;
}
//均值滤波(高斯噪声)
void week1_qt::my_MeanBlur()
{
Mat img = week1_qt::addGaussianNoise();
int sizey =img.cols; //读取图像大小
int sizex = img.rows;
Mat junzhi = Mat(sizex, sizey, CV_8UC1);//创建均值滤波图像
Mat gray = Mat(sizex, sizey, CV_8UC1);//创建灰度图
if (img.channels() == 1)
{
gray = img.clone();
}
else if (img.channels() == 3 || img.channels() == 4)//第四通道表示透明度
{
cvtColor(img, gray, CV_RGB2GRAY);
}
else
{
throw "error";
}
//均值滤波
imshow("加高斯噪声的灰度图", gray);
for (int x = 1; x < sizex - 1; x++)
{
for (int y = 1; y < sizey - 1; y++)
{
int xp = x + 1;
int yp = y + 1;
int xm = x - 1;
int ym = y - 1;
junzhi.at<uchar>(x, y) = (gray.at<uchar>(xm, ym) + gray.at<uchar>(x, ym) + gray.at<uchar>(xp, ym) + gray.at<uchar>(xm, y) + gray.at<uchar>(x, y) + gray.at<uchar>(xp, y) + gray.at<uchar>(xm, yp) + gray.at<uchar>(x, yp) + gray.at<uchar>(xp, yp)) / 9;
}
}
imshow("均值滤波(高斯噪声)", junzhi);
}
//最大最小值滤波(椒盐噪声)
void week1_qt::my_MaxMinBlur()
{
Mat img = week1_qt::addSaltNoise();
int sizey = img.cols; //读取图像大小
int sizex = img.rows;
Mat zuidazuixiaozhi = Mat(sizex, sizey, CV_8UC1);//创建最大最小值滤波图像
Mat gray = Mat(sizex, sizey, CV_8UC1);//创建灰度图
if (img.channels() == 1)
{
gray = img.clone();
}
else if (img.channels() == 3 || img.channels() == 4)//第四通道表示透明度
{
cvtColor(img, gray, CV_RGB2GRAY);
}
else
{
throw "error";
}
//最大最小值滤波
imshow("加椒盐噪声的灰度图", gray);
for (int x = 1; x < sizex - 1; x++)
{
for (int y = 1; y < sizey - 1; y++)
{
int xp = x + 1;
int yp = y + 1;
int xm = x - 1;
int ym = y - 1;
int kernal[9] = { 0 };
kernal[0] = gray.at<uchar>(xm, ym); kernal[1] = gray.at<uchar>(x, ym); kernal[2] = gray.at<uchar>(xp, ym);
kernal[3] = gray.at<uchar>(xm, y); kernal[4] = gray.at<uchar>(x, y); kernal[5] = gray.at<uchar>(xp, y);
kernal[6] = gray.at<uchar>(xm, yp); kernal[7] = gray.at<uchar>(x, yp); kernal[8] = gray.at<uchar>(xp, yp);
zuidazuixiaozhi.at<uchar>(x, y) = kernal[4];
for (int i = 0; i < 9; i++)
{
for (int j = i + 1; j < 9; j++)
{
if (kernal[i]<kernal[j]) //如果前一个元素小于后一个元素
{
int temp; //临时变量
temp = kernal[i];
kernal[i] = kernal[j]; //大的元素到前一个位置
kernal[j] = temp; //小的元素到后一个位置
}
}
}
if (gray.at<uchar>(x, y) == kernal[8])
{
zuidazuixiaozhi.at<uchar>(x, y) = kernal[7];
}
if (gray.at<uchar>(x, y) == kernal[0])
{
zuidazuixiaozhi.at<uchar>(x, y) = kernal[1];
}
}
}
imshow("最大最小值滤波(椒盐噪声)", zuidazuixiaozhi);
}
//中值滤波(椒盐噪声)
void week1_qt::my_MedianBlur()
{
Mat img = week1_qt::addSaltNoise();
int sizey = img.cols; //读取图像大小
int sizex = img.rows;
Mat zhongzhi = Mat(sizex, sizey, CV_8UC1);//创建中值滤波图像
Mat gray = Mat(sizex, sizey, CV_8UC1);//创建灰度图
if (img.channels() == 1)
{
gray = img.clone();
}
else if (img.channels() == 3 || img.channels() == 4)//第四通道表示透明度
{
cvtColor(img, gray, CV_RGB2GRAY);
}
else
{
throw "error";
}
//中值滤波
imshow("加椒盐噪声的灰度图", gray);
for (int x = 1; x < sizex - 1; x++)
{
for (int y = 1; y < sizey - 1; y++)
{
int xp = x + 1;
int yp = y + 1;
int xm = x - 1;
int ym = y - 1;
int kernal[9] = { 0 };
kernal[0] = gray.at<uchar>(xm, ym); kernal[1] = gray.at<uchar>(x, ym); kernal[2] = gray.at<uchar>(xp, ym);
kernal[3] = gray.at<uchar>(xm, y); kernal[4] = gray.at<uchar>(x, y); kernal[5] = gray.at<uchar>(xp, y);
kernal[6] = gray.at<uchar>(xm, yp); kernal[7] = gray.at<uchar>(x, yp); kernal[8] = gray.at<uchar>(xp, yp);
for (int i = 0; i < 9; i++)
{
for (int j = i + 1; j < 9; j++)
{
if (kernal[i]<kernal[j]) //如果前一个元素小于后一个元素
{
int temp; //临时变量
temp = kernal[i];
kernal[i] = kernal[j]; //大的元素到前一个位置
kernal[j] = temp; //小的元素到后一个位置
}
}
}
zhongzhi.at<uchar>(x, y) = kernal[4];
}
}
imshow("中值滤波(椒盐噪声)", zhongzhi);
}
//2、阈值分割
//阈值分割回调函数
void on_my_throwshold(int, void*)
{
//threshold(src_threshold, dst_threshold, thresholdValue, 255, 0);
dst_threshold = src_threshold.clone();
//分割图像并计算面积
w = 0;//注意:不然会累加
b = 0;
for (int i = 0; i < src_threshold.rows; i++)
{
for (int j = 0; j < src_threshold.cols; j++)
{
if ((src_threshold.at<uchar>(i, j))>thresholdValue)
{
dst_threshold.at<uchar>(i, j) = 255;
w++;
}
else
{
dst_threshold.at<uchar>(i, j) = 0;
b++;
}
}
}
imshow("阈值分割", dst_threshold);
}
//阈值分割
void week1_qt::my_threshold()
{
thresholdValue = 100;
Mat src = imread("E:/opencv project/homework/week1/data/2.jpg");
if (src.channels() == 1)
{
src_threshold = src.clone();
}
else if (src.channels() == 3 || src.channels() == 4)//第四通道表示透明度
{
cvtColor(src, src_threshold, CV_RGB2GRAY);
}
else
{
throw "error";
}
//void on_my_throwshold(int, void*);
namedWindow("阈值分割", 1);
createTrackbar("阈值", "阈值分割", &thresholdValue, 255, on_my_throwshold);
on_my_throwshold(thresholdValue, 0);
}
void week1_qt::fengemianji()
{
ui.textBrowser->insertPlainText(tr("black:%1--------").arg(b));
ui.textBrowser->insertPlainText(tr("white:%1\n").arg(w));
ui.textBrowser->moveCursor(QTextCursor::Start);
}
//3、拉伸变换
//分段线性拉伸
void week1_qt::dividedLinearStrength()
{
Mat src = imread("E:/opencv project/homework/week1/data/2.jpg", 0);
imshow("原图灰度图", src);
float x1 = 10;
float y1 = 50;
float x2 = 200;
float y2 = 150;
//计算直线参数
//L1
float K1 = y1 / x1;
//L2
float K2 = (y2 - y1) / (x2 - x1);
float B2 = y1 - K2 * x1;
//L3
float K3 = (255.0f - y2) / (255.0f - x2);
float B3 = 255.0f - K3 * 255.0f;
Mat dst = src.clone();
if (src.channels() == 1)
{
dst = src.clone();
}
else if (src.channels() == 3 || src.channels() == 4)//第四通道表示透明度
{
cvtColor(src, dst, CV_RGB2GRAY);
}
else
{
throw "error";
}
//拉伸过程
for (int i = 0; i < dst.rows; i++)
{
for (int j = 0; j < dst.cols; j++)
{
if (dst.at<uchar>(i, j) <= x1)
{
dst.at<uchar>(i, j) = K1*dst.at<uchar>(i, j);
}
else if ((dst.at<uchar>(i, j)>x1) || (dst.at<uchar>(i, j) <= x2))
{
dst.at<uchar>(i, j) = K2 * dst.at<uchar>(i, j) + B2;
}
else
{
dst.at<uchar>(i, j) = K3 * dst.at<uchar>(i, j) + B3;
}
}
}
imshow("分段线性拉伸图", dst);
//方差显示
double getVar(Mat src);
double v1 = getVar(src);
double v2 = getVar(dst);
ui.textBrowser->insertPlainText(tr("src:%1--------").arg(v1));
ui.textBrowser->insertPlainText(tr("dst:%1\n").arg(v2));
ui.textBrowser->moveCursor(QTextCursor::Start);
}
//计算图像方差
double getVar(Mat src)
{
double var;
Mat dst;
if (src.channels() == 1)
{
dst = src.clone();
}
else if (src.channels() == 3 || src.channels() == 4)//第四通道表示透明度
{
cvtColor(src, dst, CV_RGB2GRAY);
}
else
{
throw "error";
}
Mat mean;
Mat stdDev;
meanStdDev(dst, mean, stdDev);
double avg, stddev;
avg = mean.ptr<double>(0)[0];
stddev = stdDev.ptr<double>(0)[0];
return stddev * stddev;
}
void week1_qt::zhifangtulashen()
{
Mat src = imread("E:/opencv project/homework/week1/data/2.jpg", 0);
//原图直方图绘制
//参数准备
Mat dstHist;
int channels = 0;
int dims = 1;
int Num = 256;
int size[] = { Num };
float hranges[] = { 0,255 };
const float *ranges[] = { hranges };
//计算图像直方图
calcHist(&src, 1, &channels, Mat(), dstHist, dims, size, ranges);
int scale = 1;
Mat dst(Num * scale, Num, CV_8U, Scalar(0));
//获取最大值和最小值
double minValue = 0;
double maxValue = 0;
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);
//ui.textBrowser->insertPlainText(tr("dst:%1\n").arg(maxValue));
//绘制出直方图
int hpt = saturate_cast<int>(0.9 * Num);
for (int i = 0; i < Num; i++)
{
float binValue = dstHist.at<float>(i);
int realValue = saturate_cast<int>(binValue * hpt / maxValue);
rectangle(dst, Point(i * scale, Num - 1), Point((i + 1)*scale - 1, Num - realValue), Scalar(255));
}
imshow("原灰度图", src);
imshow("原图直方图", dst);
//直方图拉伸变换
int threshold = 2000;
Mat lashen = src.clone();//拉伸图像
Mat lashenHist ;//拉伸直方图
//求左边界
int grayMin = 0;
for (int i = 0; i < 256; i++)
{
float binValue = dstHist.at<float>(i);
if (binValue > threshold)
{
grayMin = i;
break;
}
//ui.textBrowser->insertPlainText(tr("dst:%1\n").arg(binValue));
}
//求右边界
int grayMax = 0;
for (int i = 255; i >= 0; i--)
{
float binValue = dstHist.at<float>(i);
if (binValue > threshold)
{
grayMax = i;
break;
}
}
int a = 0;
int z = 0;
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
int value = src.at<uchar>(i, j);
if (value < grayMin)
{
lashen.at<uchar>(i, j) = 0;
}
else if (value > grayMax)
{
lashen.at<uchar>(i, j) = 255;
}
else
{
lashen.at<uchar>(i, j) = (value - grayMin) * 255 / (grayMax - grayMin);
}
}
}
imshow("直方图拉伸图像", lashen);
lashenHist = Histogram(lashen);
imshow("直方图拉伸灰度图", lashenHist);
double v1 = getVar(src);
double v2 = getVar(lashen);
ui.textBrowser->insertPlainText(tr("src:%1--------").arg(v1));
ui.textBrowser->insertPlainText(tr("dst:%1\n").arg(v2));
ui.textBrowser->moveCursor(QTextCursor::Start);
}
//4、区域生长法
void week1_qt::RegionGrow()
{
Mat src = imread("E:/opencv project/homework/week1/data/2.jpg");
Mat srcc;
int th = 30;//阈值
// 原图
if (src.channels() == 1)
{
srcc = src.clone();
}
else if (src.channels() == 3 || src.channels() == 4)//第四通道表示透明度
{
cvtColor(src, srcc, CV_RGB2GRAY);
}
else
{
throw "error";
}
imshow("区域生长原灰度图", srcc);
// 结果图
Mat res = Mat::zeros(srcc.rows, srcc.cols, CV_8U);
// 用于标记是否遍历过某点
Mat flagMat;
res.copyTo(flagMat);
// 初始3个种子点,任选
stack<Point> seeds;
seeds.push(Point(0, 0));
seeds.push(Point(186, 166));
seeds.push(Point(327, 43));
res.at<uchar>(0, 0) = 255;
res.at<uchar>(166, 186) = 255;
res.at<uchar>(43, 327) = 255;
while (!seeds.empty())
{
Point seed = seeds.top();
seeds.pop();
// 标记为已遍历过的点
flagMat.at<uchar>(seed.y, seed.x) = 1;
// 遍历8邻域
for (size_t i = 0; i < 8; i++)
{
int tmpx = seed.x + connects[i].x;
int tmpy = seed.y + connects[i].y;
if (tmpx < 0 || tmpy < 0 || tmpx >= srcc.cols || tmpy >= srcc.rows)
continue;
// 前景点(邻域所有像素差值均小于阈值)且没有被标记过的点
if ((abs(srcc.at<uchar>(seed.y, seed.x) - res.at<uchar>(tmpy, tmpx)) < th) && flagMat.at<uchar>(tmpy, tmpx) == 0)
{
res.at<uchar>(tmpy, tmpx) = 255; // 生长
flagMat.at<uchar>(tmpy, tmpx) = 1; // 标记
seeds.push(Point(tmpx, tmpy)); // 种子压栈
}
}
}
imshow("区域生长法", res);
}
//第三次作业
//边缘检测
//sobel算子
void week1_qt::my_sobel()
{
Mat image = imread("E:/opencv project/homework/week1/data/2.jpg", 0);
imshow("边缘检测原图", image);
Mat imageX = Mat::zeros(image.size(), CV_16SC1);
Mat imageY = Mat::zeros(image.size(), CV_16SC1);
Mat imageXY = Mat::zeros(image.size(), CV_16SC1);
Mat imageX8UC;
Mat imageY8UC;
Mat imageXY8UC;
GaussianBlur(image, image, Size(3, 3), 0); //高斯滤波消除噪点
uchar *P = image.data;
uchar *PX = imageX.data;
uchar *PY = imageY.data;
int step = image.step;
int stepXY = imageX.step;
for (int i = 1; i<image.rows - 1; i++)
{
for (int j = 1; j<image.cols - 1; j++)
{
//通过指针遍历图像上每一个像素
PX[i*imageX.step + j*(stepXY / step)] = abs(P[(i - 1)*step + j + 1] + P[i*step + j + 1] * 2 + P[(i + 1)*step + j + 1] - P[(i - 1)*step + j - 1] - P[i*step + j - 1] * 2 - P[(i + 1)*step + j - 1]);
PY[i*imageX.step + j*(stepXY / step)] = abs(P[(i + 1)*step + j - 1] + P[(i + 1)*step + j] * 2 + P[(i + 1)*step + j + 1] - P[(i - 1)*step + j - 1] - P[(i - 1)*step + j] * 2 - P[(i - 1)*step + j + 1]);
}
}
addWeighted(imageX, 0.5, imageY, 0.5, 0, imageXY);//融合X、Y方向
convertScaleAbs(imageX, imageX8UC);
convertScaleAbs(imageY, imageY8UC);
convertScaleAbs(imageXY, imageXY8UC); //转换为8bit图像
imshow("sobel算子", imageXY8UC);
}
//prewitt算子
void week1_qt::my_prewitt()
{
Mat image = imread("E:/opencv project/homework/week1/data/2.jpg", 0);
Mat imageX = Mat::zeros(image.size(), CV_16SC1);
Mat imageY = Mat::zeros(image.size(), CV_16SC1);
Mat imageXY = Mat::zeros(image.size(), CV_16SC1);
Mat imageX8UC;
Mat imageY8UC;
Mat imageXY8UC;
GaussianBlur(image, image, Size(3, 3), 0); //高斯滤波消除噪点
uchar *P = image.data;
uchar *PX = imageX.data;
uchar *PY = imageY.data;
int step = image.step;
int stepXY = imageX.step;
for (int i = 1; i<image.rows - 1; i++)
{
for (int j = 1; j<image.cols - 1; j++)
{
//通过指针遍历图像上每一个像素
PX[i*imageX.step + j*(stepXY / step)] = abs(P[(i - 1)*step + j + 1] + P[i*step + j + 1] + P[(i + 1)*step + j + 1] - P[(i - 1)*step + j - 1] - P[i*step + j - 1] - P[(i + 1)*step + j - 1]);
PY[i*imageX.step + j*(stepXY / step)] = abs(P[(i + 1)*step + j - 1] + P[(i + 1)*step + j] + P[(i + 1)*step + j + 1] - P[(i - 1)*step + j - 1] - P[(i - 1)*step + j] - P[(i - 1)*step + j + 1]);
}
}
addWeighted(imageX, 0.5, imageY, 0.5, 0, imageXY);//融合X、Y方向
convertScaleAbs(imageX, imageX8UC);
convertScaleAbs(imageY, imageY8UC);
convertScaleAbs(imageXY, imageXY8UC); //转换为8bit图像
imshow("prewitt算子", imageXY8UC);
}
//roberts算子
void week1_qt::my_roberts()
{
Mat image = imread("E:/opencv project/homework/week1/data/2.jpg", 0);
Mat imageX = Mat::zeros(image.size(), CV_16SC1);
Mat imageY = Mat::zeros(image.size(), CV_16SC1);
Mat imageXY = Mat::zeros(image.size(), CV_16SC1);
Mat imageX8UC;
Mat imageY8UC;
Mat imageXY8UC;
GaussianBlur(image, image, Size(3, 3), 0); //高斯滤波消除噪点
uchar *P = image.data;
uchar *PX = imageX.data;
uchar *PY = imageY.data;
int step = image.step;
int stepXY = imageX.step;
for (int i = 1; i<image.rows - 1; i++)
{
for (int j = 1; j<image.cols - 1; j++)
{
//通过指针遍历图像上每一个像素
PX[i*imageX.step + j*(stepXY / step)] = abs(P[(i + 1)*step + j + 1] - P[i*step + j]);
PY[i*imageX.step + j*(stepXY / step)] = abs(P[i*step + j + 1] - P[(i + 1)*step + j]);
}
}
addWeighted(imageX, 0.5, imageY, 0.5, 0, imageXY);//融合X、Y方向
convertScaleAbs(imageX, imageX8UC);
convertScaleAbs(imageY, imageY8UC);
convertScaleAbs(imageXY, imageXY8UC); //转换为8bit图像
imshow("roberts算子", imageXY8UC);
}
//2、二值图像及其边界提取
void week1_qt::my_boder()
{
Mat src = imread("E:/opencv project/homework/week1/data/3.jpg");
imshow("边界提取原图", src);
//转成二值图像
Mat src_boder;
if (src.channels() == 1)
{
src_boder = src.clone();
}
else if (src.channels() == 3 || src.channels() == 4)//第四通道表示透明度
{
cvtColor(src, src_boder, CV_RGB2GRAY);
}
else
{
throw "error";
}
threshold(src_boder, src_boder, 150, 255, THRESH_BINARY);
//腐蚀操作
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
Mat dst;
erode(src_boder, dst, element);
//相减
absdiff(src_boder, dst, dst);
imshow("边界提取", dst);
//计算各分割图像面积及边界长度
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;
//找到轮廓
findContours(dst, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
/*
//计算矩
vector<Moments> mu(g_vContours.size());
for (unsigned int i = 0; i < g_vContours.size(); i++)
{
mu[i] = moments(g_vContours[i], false);
//
}
//计算中心矩
vector<Point2f> mc(g_vContours.size());
for (unsigned int i = 0; i < g_vContours.size(); i++)
{
mc[i] = Point2f(static_cast<float>(mu[i].m10 / mu[i].m00), static_cast<float>(mu[i].m01 / mu[i].m00));
}
*/
//计算轮廓长度面积
for (int i = 0; i < g_vContours.size(); i++)
{
double area1 = contourArea(g_vContours[i]);
double length1 = arcLength(g_vContours[i], true);
ui.textBrowser->insertPlainText(tr("boder's length:%1--------").arg(length1));
ui.textBrowser->insertPlainText(tr("area :%1\n").arg(area1));
ui.textBrowser->moveCursor(QTextCursor::Start);
}
/*
Mat Inputimage = dst;
int a[1000];
int m = 0, n;
map<int, int> colors;
int rows = Inputimage.rows;
int cols = Inputimage.cols;
for (int i = 0; i < rows; i++)
{
const int* data_src = (int*)Inputimage.ptr<int>(i);
for (int j = 0; j < cols; j++)
{
int pixelValue = data_src[j];
if (pixelValue > 1)
{
if (colors.count(pixelValue) <= 0)
{
colors[pixelValue] = m;
a[m] = 0;
m++;
}
n = colors[pixelValue];
a[n]++;
}
}
}
for (int o = 0; o < m; o++)
if (a[o] > 600)
{
ui.textBrowser->insertPlainText(tr("boder's length:%1--------").arg(a[o] / 4));
ui.textBrowser->insertPlainText(tr("area :%1\n").arg(a[o]));
ui.textBrowser->moveCursor(QTextCursor::Start);
}
*/
}
//3、区域骨架提取
void week1_qt::gujiatiqu()
{
//读入灰度图像
Mat src = imread("E:/opencv project/homework/week1/data/4.jpg", 0);
imshow("原始图像", src);
//二值化处理
GaussianBlur(src, src, Size(7, 7), 0, 0);//高斯滤波
threshold(src, src, 140, 1, cv::THRESH_BINARY);//二值化,前景为1,背景为0
vector<Point2i> point1;
while (1)
{
//计算删除点个数
int c0 = 0;
//进行第一遍条件检测,判断是否删除该白点
for (int x = 1; x < src.rows - 1; x++)
{
for (int y = 1; y < src.cols - 1; y++)
{
//白点
if (src.at<uchar>(x, y) == 1)
{
//计算条件一:黑点数2和6之间
int c1 = 0;
c1 = src.at<uchar>(x - 1, y - 1) + src.at<uchar>(x, y - 1) + src.at<uchar>(x + 1, y - 1) + src.at<uchar>(x - 1, y) + src.at<uchar>(x + 1, y) + src.at<uchar>(x - 1, y + 1) + src.at<uchar>(x, y + 1) + src.at<uchar>(x + 1, y + 1);
//c1 = 8 - c1;
if (c1 >= 2 && c1 <= 6)
{
//计算条件二:顺时针0,1个数为1
int c2 = 0;
if (src.at<uchar>(x - 1, y - 1) == 0 && src.at<uchar>(x, y - 1) == 1) ++c2;
if (src.at<uchar>(x, y - 1) == 0 && src.at<uchar>(x + 1, y - 1) == 1) ++c2;
if (src.at<uchar>(x + 1, y - 1) == 0 && src.at<uchar>(x + 1, y) == 1) ++c2;
if (src.at<uchar>(x + 1, y) == 0 && src.at<uchar>(x + 1, y + 1) == 1) ++c2;
if (src.at<uchar>(x + 1, y + 1) == 0 && src.at<uchar>(x, y + 1) == 1) ++c2;
if (src.at<uchar>(x, y + 1) == 0 && src.at<uchar>(x - 1, y + 1) == 1) ++c2;
if (src.at<uchar>(x - 1, y + 1) == 0 && src.at<uchar>(x - 1, y) == 1) ++c2;
if (src.at<uchar>(x - 1, y) == 0 && src.at<uchar>(x - 1, y - 1) == 1) ++c2;
if (c2 == 1)
{
//计算条件三:p2*p4*p6=0
int c3 = src.at<uchar>(x, y - 1)*src.at<uchar>(x + 1, y)*src.at<uchar>(x, y + 1);
if (c3 == 0)
{
//计算条件四:p4*p6*p8=0
int c4 = src.at<uchar>(x - 1, y)*src.at<uchar>(x + 1, y)*src.at<uchar>(x, y + 1);
if (c4 == 0)
{
//删掉该点
//src.at<uchar>(x, y) = 0;
Point2i p;
p.x = x;
p.y = y;
point1.push_back(p);
c0++;
}
}
}
}
}
}
}
for (vector<Point2i>::iterator i = point1.begin(); i != point1.end(); ++i)
{
src.at<uchar>(i->x, i->y) = 0;
}
//第二遍循环检测
for (int x = 1; x < src.rows - 1; x++)
{
for (int y = 1; y < src.cols - 1; y++)
{
//白点
if (src.at<uchar>(x, y) == 1)
{
//计算条件一:黑点数2和6之间
int c1 = 0;
c1 = src.at<uchar>(x - 1, y - 1) + src.at<uchar>(x, y - 1) + src.at<uchar>(x + 1, y - 1) + src.at<uchar>(x - 1, y) + src.at<uchar>(x + 1, y) + src.at<uchar>(x - 1, y + 1) + src.at<uchar>(x, y + 1) + src.at<uchar>(x + 1, y + 1);
//c1 = 8 - c1;
if (c1 >= 2 && c1 <= 6)
{
//计算条件二:顺时针0,1个数为1
int c2 = 0;
if (src.at<uchar>(x - 1, y - 1) == 0 && src.at<uchar>(x, y - 1) == 1) ++c2;
if (src.at<uchar>(x, y - 1) == 0 && src.at<uchar>(x + 1, y - 1) == 1) ++c2;
if (src.at<uchar>(x + 1, y - 1) == 0 && src.at<uchar>(x + 1, y) == 1) ++c2;
if (src.at<uchar>(x + 1, y) == 0 && src.at<uchar>(x + 1, y + 1) == 1) ++c2;
if (src.at<uchar>(x + 1, y + 1) == 0 && src.at<uchar>(x, y + 1) == 1) ++c2;
if (src.at<uchar>(x, y + 1) == 0 && src.at<uchar>(x - 1, y + 1) == 1) ++c2;
if (src.at<uchar>(x - 1, y + 1) == 0 && src.at<uchar>(x - 1, y) == 1) ++c2;
if (src.at<uchar>(x - 1, y) == 0 && src.at<uchar>(x - 1, y - 1) == 1) ++c2;
if (c2 == 1)
{
//计算条件三:p2*p4*p8=0
int c3 = src.at<uchar>(x, y - 1)*src.at<uchar>(x + 1, y)*src.at<uchar>(x - 1, y);
if (c3 == 0)
{
//计算条件四:p2*p6*p8=0
int c4 = src.at<uchar>(x - 1, y)*src.at<uchar>(x, y - 1)*src.at<uchar>(x, y + 1);
if (c4 == 0)
{
//删掉该点
//src.at<uchar>(x, y) = 0;
Point2i p;
p.x = x;
p.y = y;
point1.push_back(p);
c0++;
}
}
}
}
}
}
}
for (vector<Point2i>::iterator i = point1.begin(); i != point1.end(); ++i)
{
src.at<uchar>(i->x, i->y) = 0;
}
//循环,直到没有满足要求的删除点
if (c0 == 0)
{
break;
}
}
//显示细化后图像
Mat dst = src * 255;//二值转为灰度图显示
imshow("细化图像", dst);
//查找交叉点
Mat src1 = src * 255;
vector<Point2i> point;
//{
int c0 = 0;
//交叉点检测
for (int x = 1; x < src1.rows - 1; x++)
{
for (int y = 1; y < src1.cols - 1; y++)
{
//白点
if (src1.at<uchar>(x, y) == 255)
{
//判断是否为端点:周围只有一个白点连接
int c1 = 0;
c1 = src1.at<uchar>(x - 1, y - 1) + src1.at<uchar>(x, y - 1) + src1.at<uchar>(x + 1, y - 1) + src1.at<uchar>(x - 1, y) + src1.at<uchar>(x + 1, y) + src1.at<uchar>(x - 1, y + 1) + src1.at<uchar>(x, y + 1) + src1.at<uchar>(x + 1, y + 1);
if (c1 == 255)
{
//端点
Point2i p;
p.x = x;
p.y = y;
point.push_back(p);
}
//判断是否为交叉点:大于某个阈值
int c2 = 0;
if (src1.at<uchar>(x - 1, y - 1) == 0 && src1.at<uchar>(x, y - 1) == 255) ++c2;
if (src1.at<uchar>(x, y - 1) == 0 && src1.at<uchar>(x + 1, y - 1) == 255) ++c2;
if (src1.at<uchar>(x + 1, y - 1) == 0 && src1.at<uchar>(x + 1, y) == 255) ++c2;
if (src1.at<uchar>(x + 1, y) == 0 && src1.at<uchar>(x + 1, y + 1) == 255) ++c2;
if (src1.at<uchar>(x + 1, y + 1) == 0 && src1.at<uchar>(x, y + 1) == 255) ++c2;
if (src1.at<uchar>(x, y + 1) == 0 && src1.at<uchar>(x - 1, y + 1) == 255) ++c2;
if (src1.at<uchar>(x - 1, y + 1) == 0 && src1.at<uchar>(x - 1, y) == 255) ++c2;
if (src.at<uchar>(x - 1, y) == 0 && src1.at<uchar>(x - 1, y - 1) == 255) ++c2;
if (c2 >= 3)
{
//画交叉点
Point2i p;
p.x = x;
p.y = y;
point.push_back(p);
}
}
}
}
//画交叉点
for (vector<Point2i>::iterator i = point.begin(); i != point.end(); ++i)
{
circle(src1, Point2i(i->y, i->x), 5, Scalar(255));
}
//显示细化后图像
imshow("交叉点图像", src1);
}
//第四次作业
//1、腐蚀膨胀
//图像腐蚀
Mat my_erode()
{
Mat src = imread("E:/opencv project/homework/week1/data/5.jpg", 0);
imshow("原图", src);
threshold(src, src, 140, 1, cv::THRESH_BINARY);//二值化,前景为1,背景为0
/*
//显示结构元素
cout << "结构元素" << endl;
cout << "0" << " " << "1" << " " << "0" << endl;
cout << "1" << " " << "1" << " " << "1" << endl;
cout << "0" << " " << "1" << " " << "0" << endl;
*/
//全黑图像
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC1);
vector<Point2i> point1;//腐蚀元素
for (int x = 1; x < src.rows - 1; x++)
{
for (int y = 1; y < src.cols - 1; y++)
{
//定义8邻域
int pixel[9];
pixel[0] = src.at<uchar>(x - 1, y - 1);
pixel[1] = src.at<uchar>(x, y - 1);
pixel[2] = src.at<uchar>(x, y + 1);
pixel[3] = src.at<uchar>(x - 1, y);
pixel[4] = src.at<uchar>(x, y);
pixel[5] = src.at<uchar>(x + 1, y);
pixel[6] = src.at<uchar>(x - 1, y + 1);
pixel[7] = src.at<uchar>(x, y + 1);
pixel[8] = src.at<uchar>(x + 1, y + 1);
if (pixel[1] && pixel[3] && pixel[4] && pixel[5] && pixel[7])
{
Point2i p;
p.x = x;
p.y = y;
point1.push_back(p);
}
}
}
//腐蚀结果
for (vector<Point2i>::iterator i = point1.begin(); i != point1.end(); ++i)
{
dst.at<uchar>(i->x, i->y) = 1;
}
dst = dst * 255;
return dst;
}
//图像膨胀
Mat my_dilate()
{
Mat src = imread("E:/opencv project/homework/week1/data/5.jpg", 0);
threshold(src, src, 140, 1, cv::THRESH_BINARY);//二值化,前景为1,背景为0
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC1);
vector<Point2i> point2;//膨胀元素
for (int x = 1; x < src.rows - 1; x++)
{
for (int y = 1; y < src.cols - 1; y++)
{
//定义8邻域
int pixel[9];
pixel[0] = src.at<uchar>(x - 1, y - 1);
pixel[1] = src.at<uchar>(x, y - 1);
pixel[2] = src.at<uchar>(x, y + 1);
pixel[3] = src.at<uchar>(x - 1, y);
pixel[4] = src.at<uchar>(x, y);
pixel[5] = src.at<uchar>(x + 1, y);
pixel[6] = src.at<uchar>(x - 1, y + 1);
pixel[7] = src.at<uchar>(x, y + 1);
pixel[8] = src.at<uchar>(x + 1, y + 1);
if (pixel[1] && pixel[3] && pixel[4] && pixel[5] && pixel[7])
{
Point2i p;
p.x = x;
p.y = y;
point2.push_back(p);
}
}
}
//膨胀结果
for (vector<Point2i>::iterator i = point2.begin(); i != point2.end(); ++i)
{
dst.at<uchar>(i->x, i->y) = 1;
dst.at<uchar>(i->x, i->y - 1) = 1;
dst.at<uchar>(i->x - 1, i->y) = 1;
dst.at<uchar>(i->x + 1, i->y) = 1;
dst.at<uchar>(i->x, i->y + 1) = 1;
}
dst = dst * 255;
return dst;
}
void week1_qt::fushipengzhang()
{
//差图
Mat my_erode();
Mat dst1 = my_erode();
imshow("腐蚀图像", dst1);
Mat my_dilate();
Mat dst2 = my_dilate();
imshow("膨胀图像", dst2);
Mat dst3 = dst2 - dst1;
imshow("差图", dst3);
imwrite("20.jpg", dst3);
//显示结构元素
ui.textBrowser->insertPlainText(tr("0 1 0\n"));
ui.textBrowser->insertPlainText(tr("1 1 1\n"));
ui.textBrowser->insertPlainText(tr("0 1 0\n"));
ui.textBrowser->moveCursor(QTextCursor::Start);
}
//直线检测
void week1_qt::line_detect()
{
Mat my_erode();
Mat dst1 = my_erode();
Mat my_dilate();
Mat dst2 = my_dilate();
Mat src = dst2 - dst1;
imshow("边缘检测后", src);
threshold(src, src, 140, 1, cv::THRESH_BINARY);//二值化,前景为1,背景为0
int **count;//用于统计个数,θ取值[0到360)
int lmax = (int)sqrt(src.rows*src.rows + src.cols + src.cols);//距离的最大值
//初始化极坐标
count = new int*[359];
for (int i = 0; i < 359; i++)
{
count[i] = new int[lmax];
memset(count[i], 0, sizeof(int)*lmax);
}
//统计count的值
for (int x = 0; x < src.rows; x++)
{
for (int y = 0; y < src.cols; y++)
{
if (src.at<uchar>(x, y) == 1)
{
//找出对应的所有θ和p值
for (int theta = 0; theta < 359; theta++)
{
int L = (int)((x*cos(theta * CV_PI / 180) + y*sin(theta * CV_PI / 180)));
if (L > 0 && L < lmax)
{
count[theta][L]++;
}
}
}
}
}
//阈值处理
Point2i **p;//画直线用储存点
//初始化
p = new Point2i*[359];
for (int i = 0; i < 359; i++)
{
p[i] = new Point2i[lmax];
memset(p[i], (0, 0), sizeof(Point2i)*lmax);
}
src = 50 * src;
int th = 80;
int c = 0;//统计直线个数
for (int i = 0; i < 359; i++)
{
for (int j = 0; j < lmax; j++)
{
if (count[i][j]>th)
{
//认为检测到一条直线
c++;
ui.textBrowser->insertPlainText(tr("Line%1:").arg(c)); ui.textBrowser->insertPlainText(tr("%1\n").arg(count[i][j]));
ui.textBrowser->moveCursor(QTextCursor::Start);
//cout << "直线" << c << "的长度为:" << count[i][j];
//画直线
for (int x = 0; x < src.rows; x++)
{
for (int y = 0; y < src.cols; y++)
{
if (src.at<uchar>(x, y) == 50)
{
if (j == (int)((x*cos(i * CV_PI / 180) + y*sin(i * CV_PI / 180))))
{
Point2i p1;
p1.x = y;
p1.y = x;
if (p[i][j].x == 0 && p[i][j].y == 0)
{
p[i][j] = p1;
}
else
{
Point2i p2;
p2 = p[i][j];
line(src, p1, p2, Scalar(255), 1);
}
}
}
}
}
}
}
}
imshow("检测直线", src);
}
//3、应用
Mat my_erode1(Mat src1)//灰度
{
Mat src;
threshold(src1, src, 140, 1, cv::THRESH_BINARY);//二值化,前景为1,背景为0
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC1);
vector<Point2i> point1;//腐蚀元素
for (int x = 1; x < src.rows - 1; x++)
{
for (int y = 1; y < src.cols - 1; y++)
{
//定义8邻域
int pixel[9];
pixel[0] = src.at<uchar>(x - 1, y - 1);
pixel[1] = src.at<uchar>(x, y - 1);
pixel[2] = src.at<uchar>(x, y + 1);
pixel[3] = src.at<uchar>(x - 1, y);
pixel[4] = src.at<uchar>(x, y);
pixel[5] = src.at<uchar>(x + 1, y);
pixel[6] = src.at<uchar>(x - 1, y + 1);
pixel[7] = src.at<uchar>(x, y + 1);
pixel[8] = src.at<uchar>(x + 1, y + 1);
if (pixel[1] && pixel[2] && pixel[3] && pixel[4] && pixel[5] && pixel[6] && pixel[7] && pixel[8] && pixel[9])
{
Point2i p;
p.x = x;
p.y = y;
point1.push_back(p);
}
}
}
//腐蚀结果
for (vector<Point2i>::iterator i = point1.begin(); i != point1.end(); ++i)
{
dst.at<uchar>(i->x, i->y) = 1;
}
dst = dst * 255;
return dst;
}
//图像膨胀
Mat my_dilate1(Mat src1)//灰度
{
Mat src;
threshold(src1, src, 140, 1, cv::THRESH_BINARY);//二值化,前景为1,背景为0
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC1);
vector<Point2i> point2;//膨胀元素
for (int x = 1; x < src.rows - 1; x++)
{
for (int y = 1; y < src.cols - 1; y++)
{
//定义8邻域
int pixel[9];
pixel[0] = src.at<uchar>(x - 1, y - 1);
pixel[1] = src.at<uchar>(x, y - 1);
pixel[2] = src.at<uchar>(x, y + 1);
pixel[3] = src.at<uchar>(x - 1, y);
pixel[4] = src.at<uchar>(x, y);
pixel[5] = src.at<uchar>(x + 1, y);
pixel[6] = src.at<uchar>(x - 1, y + 1);
pixel[7] = src.at<uchar>(x, y + 1);
pixel[8] = src.at<uchar>(x + 1, y + 1);
if (pixel[1] && pixel[2] && pixel[3] && pixel[4] && pixel[5] && pixel[6] && pixel[7] && pixel[8] && pixel[9])
{
Point2i p;
p.x = x;
p.y = y;
point2.push_back(p);
}
}
}
//膨胀结果
for (vector<Point2i>::iterator i = point2.begin(); i != point2.end(); ++i)
{
dst.at<uchar>(i->x - 1, i->y - 1) = 1;
dst.at<uchar>(i->x, i->y - 1) = 1;
dst.at<uchar>(i->x, i->y + 1) = 1;
dst.at<uchar>(i->x - 1, i->y) = 1;
dst.at<uchar>(i->x, i->y) = 1;
dst.at<uchar>(i->x + 1, i->y) = 1;
dst.at<uchar>(i->x - 1, i->y + 1) = 1;
dst.at<uchar>(i->x, i->y + 1) = 1;
dst.at<uchar>(i->x + 1, i->y + 1) = 1;
}
dst = dst * 255;
return dst;
}
//开运算
Mat kai(Mat src)
{
//腐蚀
Mat my_erode1(Mat src);
Mat dst1 = my_erode1(src);
//膨胀
Mat my_dilate1(Mat src);
Mat dst2 = my_dilate1(dst1);
//结果显示
//imshow("开运算结果", dst2);
return dst2;
}
//闭运算
Mat bi(Mat src)
{
//膨胀
Mat my_dilate1(Mat src);
Mat dst1 = my_dilate1(src);
//腐蚀
Mat my_erode1(Mat src);
Mat dst2 = my_erode1(dst1);
//结果显示
//imshow("闭运算结果", dst2);
return dst2;
}
//形态学滤波
void week1_qt::lvbo()
{
//读图
Mat src = imread("E:/opencv project/homework/week1/data/20.png", 0);
imshow("原图", src);
//开运算去噪
Mat kai(Mat src1);
Mat k = kai(src);
imshow("开运算结果", k);
//闭运算修复断裂
Mat bi(Mat src1);
Mat b1 = bi(src);
imshow("闭运算结果", b1);
Mat b = bi(k);
//结果显示
imshow("滤波结果", b);
}
//第五次作业
//1、2、边界线链码及周长面积计算
void week1_qt::lianma()
{
//读图
Mat src = imread("E:/opencv project/homework/week1/data/5.jpg", 0);//腐蚀膨胀差图
threshold(src, src, 140, 255, cv::THRESH_BINARY);//二值化,前景为1,背景为0
imshow("原图", src);
//链码图像
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC1);
vector<Point2i> bianyuan;
//步骤一;找b0,c0
Point2i b0;
b0.x = 0;
b0.y = 0;
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
if ((src.at<uchar>(i, j) == 255) && (b0.x == 0 && b0.y == 0))
{
b0.x = i;
b0.y = j;
}
}
}
circle(dst, Point2i(b0.y, b0.x), 5, Scalar(255));
Point2i c0;
c0.x = b0.x;
c0.y = b0.y - 1;
//迭代点
Point2i b;
Point2i c;
//步骤二:找b1,c1
Point2i b1;
Point2i c1;
b.x = c0.x;
b.y = c0.y;
dst.at<uchar>(b.x, b.y) = 255;
//链码
vector<int> lianma;
int ma = 4;
for (int i = 0; i < 8; i++)
{
if (ma == 0)
{
c.x = b.x;
c.y = b.y;
b.x = b.x + 1;
b.y = b.y;
ma = 7;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
}
if (ma == 1)
{
c.x = b.x;
c.y = b.y;
b.x = b.x + 1;
b.y = b.y;
ma = 0;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
}
if (ma == 2)
{
c.x = b.x;
c.y = b.y;
b.x = b.x;
b.y = b.y + 1;
ma = 1;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
}
if (ma == 3)
{
c.x = b.x;
c.y = b.y;
b.x = b.x;
b.y = b.y + 1;
ma = 2;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
}
if (ma == 4)
{
c.x = b.x;
c.y = b.y;
b.x = b.x - 1;
b.y = b.y;
ma = 3;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
}
if (ma == 5)
{
c.x = b.x;
c.y = b.y;
b.x = b.x - 1;
b.y = b.y;
ma = 4;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
}
if (ma == 6)
{
c.x = b.x;
c.y = b.y;
b.x = b.x;
b.y = b.y - 1;
ma = 5;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
}
if (ma == 7)
{
c.x = b.x;
c.y = b.y;
b.x = b.x;
b.y = b.y - 1;
ma = 6;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
}
}
b1.x = b.x;
b1.y = b.y;
c1.x = c.x;
c1.y = c.y;
dst.at<uchar>(b.x, b.y) = 255;
lianma.push_back(ma);
bianyuan.push_back(b0);
bianyuan.push_back(b1);
//步骤三:循环查找
while (1)//条件
{
//初始化新码
if (c.x == b.x&&c.y == b.y + 1)
{
ma = 0;
}
if (c.x == b.x - 1 && c.y == b.y + 1)
{
ma = 1;
}
if (c.x == b.x - 1 && c.y == b.y)
{
ma = 2;
}
if (c.x == b.x - 1 && c.y == b.y - 1)
{
ma = 3;
}
if (c.x == b.x&&c.y == b.y - 1)
{
ma = 4;
}
if (c.x == b.x + 1 && c.y == b.y - 1)
{
ma = 5;
}
if (c.x == b.x + 1 && c.y == b.y)
{
ma = 6;
}
if (c.x == b.x + 1 && c.y == b.y + 1)
{
ma = 7;
}
//新的b,c查找
b.x = c.x;
b.y = c.y;
for (int i = 0; i < 8; i++)
{
if (ma == 0)
{
c.x = b.x;
c.y = b.y;
b.x = b.x + 1;
b.y = b.y;
ma = 7;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
continue;
}
if (ma == 1)
{
c.x = b.x;
c.y = b.y;
b.x = b.x + 1;
b.y = b.y;
ma = 0;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
continue;
}
if (ma == 2)
{
c.x = b.x;
c.y = b.y;
b.x = b.x;
b.y = b.y + 1;
ma = 1;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
continue;
}
if (ma == 3)
{
c.x = b.x;
c.y = b.y;
b.x = b.x;
b.y = b.y + 1;
ma = 2;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
continue;
}
if (ma == 4)
{
c.x = b.x;
c.y = b.y;
b.x = b.x - 1;
b.y = b.y;
ma = 3;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
continue;
}
if (ma == 5)
{
c.x = b.x;
c.y = b.y;
b.x = b.x - 1;
b.y = b.y;
ma = 4;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
continue;
}
if (ma == 6)
{
c.x = b.x;
c.y = b.y;
b.x = b.x;
b.y = b.y - 1;
ma = 5;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
continue;
}
if (ma == 7)
{
c.x = b.x;
c.y = b.y;
b.x = b.x;
b.y = b.y - 1;
ma = 6;
if (src.at<uchar>(b.x, b.y) == 255)
{
break;
}
continue;
}
}
lianma.push_back(ma);
bianyuan.push_back(b);
dst.at<uchar>(b.x, b.y) = 255;
if (bianyuan[bianyuan.size() - 1].x == b1.x && bianyuan[bianyuan.size() - 1].y == b1.y&&bianyuan[bianyuan.size() - 2].x == b0.x&&bianyuan[bianyuan.size() - 2].y == b0.y)
{
break;
}
}
imshow("边缘图", dst);
//输出链码
//cout << "链码为:" << endl;
for (int k = 0; k < lianma.size(); k++)
{
ui.textBrowser->insertPlainText(tr("%1").arg(lianma[k]));
ui.textBrowser->moveCursor(QTextCursor::Start);
//cout << lianma[k];
}
//cout << endl;
ui.textBrowser->insertPlainText(tr("lianma:\n"));
ui.textBrowser->moveCursor(QTextCursor::Start);
//计算链码长度
int j = 0;
int o = 0;
for (int i = 0; i < lianma.size(); i++)
{
if (lianma[i] % 2 == 0)
{
o++;
}
else
{
j++;
}
}
float l = o + 1.414*j;
//cout << "长度为:" << l << endl;
ui.textBrowser->insertPlainText(tr("length:%1\n").arg(l));
ui.textBrowser->moveCursor(QTextCursor::Start);
//计算区域面积
int A = 0;
for (int i = 1; i < bianyuan.size() - 1; i++)//除去最后存入的b1,b0最后测
{
int a = lianma[i - 1];//进入该点的链码
int b = lianma[i];//出该点的链码
Point2i p;
p.x = bianyuan[i].x;
p.y = bianyuan[i].y;
//判断p是上边界点还是下边界点
//上边界
if ((a == 0 && b == 0) || (a == 0 && b == 1) || (a == 0 && b == 6) || (a == 0 && b == 7) || (a == 1 && b == 0) || (a == 1 && b == 1) || (a == 1 && b == 6) || (a == 1 && b == 7) || (a == 2 && b == 0) || (a == 2 && b == 1) || (a == 2 && b == 6) || (a == 2 && b == 7) || (a == 7 && b == 0) || (a == 7 && b == 1) || (a == 7 && b == 6) || (a == 7 && b == 7))
{
A = A - p.y;
}
//既上又下
if ((a == 0 && b == 4) || (a == 0 && b == 5) || (a == 1 && b == 5) || (a == 3 && b == 0) || (a == 3 && b == 1) || (a == 3 && b == 7) || (a == 4 && b == 0) || (a == 4 && b == 1) || (a == 5 && b == 1) || (a == 7 && b == 3) || (a == 7 && b == 4) || (a == 7 && b == 5))
{
A = A + 1;
}
//下边界
if ((a == 3 && b == 2) || (a == 3 && b == 3) || (a == 3 && b == 4) || (a == 3 && b == 5) || (a == 4 && b == 2) || (a == 4 && b == 3) || (a == 4 && b == 4) || (a == 4 && b == 5) || (a == 5 && b == 2) || (a == 5 && b == 3) || (a == 5 && b == 4) || (a == 5 && b == 5) || (a == 6 && b == 2) || (a == 6 && b == 3) || (a == 6 && b == 4) || (a == 6 && b == 5))
{
A = A + p.y + 1;
}
}
//cout << "区域面积:" << A << endl;
ui.textBrowser->insertPlainText(tr("area:%1\n").arg(A));
ui.textBrowser->moveCursor(QTextCursor::Start);
}
//3、共生矩阵及特征
void week1_qt::gongsheng()
{
//灰度图
Mat src = imread("E:/opencv project/homework/week1/data/13.jpg", 0);
imshow("原图", src);
//创建原始共生矩阵
Mat dst1 = Mat::zeros(256, 256, CV_8UC1);//0
Mat dst2 = Mat::zeros(256, 256, CV_8UC1);//45
Mat dst3 = Mat::zeros(256, 256, CV_8UC1);//90
Mat dst4 = Mat::zeros(256, 256, CV_8UC1);//135
//统计和
double n1 = 0;
double n2 = 0;
double n3 = 0;
double n4 = 0;
//0
for (int x = 0; x < src.rows - 1; x++)
{
for (int y = 0; y < src.cols; y++)
{
int a = src.at<uchar>(x, y);
int b = src.at<uchar>(x + 1, y);
dst1.at<uchar>(a, b)++;
n1++;
}
}
imshow("0方向共生矩阵", dst1);
//45
for (int x = 1; x < src.rows; x++)
{
for (int y = 0; y < src.cols - 1; y++)
{
int a = src.at<uchar>(x, y);
int b = src.at<uchar>(x - 1, y + 1);
dst2.at<uchar>(a, b)++;
n2++;
}
}
imshow("45方向共生矩阵", dst2);
//90
for (int x = 0; x < src.rows; x++)
{
for (int y = 0; y < src.cols - 1; y++)
{
int a = src.at<uchar>(x, y);
int b = src.at<uchar>(x, y + 1);
dst3.at<uchar>(a, b)++;
n3++;
}
}
imshow("90方向共生矩阵", dst3);
//135
for (int x = 0; x < src.rows - 1; x++)
{
for (int y = 0; y < src.cols - 1; y++)
{
int a = src.at<uchar>(x, y);
int b = src.at<uchar>(x + 1, y + 1);
dst4.at<uchar>(a, b)++;
n4++;
}
}
imshow("135方向共生矩阵", dst4);
//计算特征
//0
//对比度
double d1 = 0;
double d2 = 0;
double d3 = 0;
double d4 = 0;
//同质性
double t1 = 0;
double t2 = 0;
double t3 = 0;
double t4 = 0;
//能量
double e1 = 0;
double e2 = 0;
double e3 = 0;
double e4 = 0;
//熵
double s1 = 0;
double s2 = 0;
double s3 = 0;
double s4 = 0;
//cout << "n:" << n1 << " " << n2 << " " << n3 << " " << n4 << endl;
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < 256; j++)
{
//对比度
d1 = d1 + (i - j)*(i - j)*dst1.at<uchar>(i, j) / n1;
d2 = d2 + (i - j)*(i - j)*dst2.at<uchar>(i, j) / n2;
d3 = d3 + (i - j)*(i - j)*dst3.at<uchar>(i, j) / n3;
d4 = d4 + (i - j)*(i - j)*dst4.at<uchar>(i, j) / n4;
//同质性
t1 = t1 + dst1.at<uchar>(i, j) / (n1*(1 + abs(i - j)));
t2 = t2 + dst2.at<uchar>(i, j) / (n2*(1 + abs(i - j)));
t3 = t3 + dst3.at<uchar>(i, j) / (n3*(1 + abs(i - j)));
t4 = t4 + dst4.at<uchar>(i, j) / (n4*(1 + abs(i - j)));
//能量
e1 = e1 + (dst1.at<uchar>(i, j) / n1)*(dst1.at<uchar>(i, j) / n1);
e2 = e2 + (dst2.at<uchar>(i, j) / n2)*(dst2.at<uchar>(i, j) / n2);
e3 = e3 + (dst3.at<uchar>(i, j) / n3)*(dst3.at<uchar>(i, j) / n3);
e4 = e4 + (dst4.at<uchar>(i, j) / n4)*(dst4.at<uchar>(i, j) / n4);
//熵
if (dst1.at<uchar>(i, j) != 0)
{
s1 = s1 - (dst1.at<uchar>(i, j) / n1)*log(dst1.at<uchar>(i, j) / n1) / log(2);
}
if (dst2.at<uchar>(i, j) != 0)
{
s2 = s2 - (dst2.at<uchar>(i, j) / n2)*log(dst2.at<uchar>(i, j) / n2) / log(2);
}
if (dst3.at<uchar>(i, j) != 0)
{
s3 = s3 - (dst3.at<uchar>(i, j) / n3)*log(dst3.at<uchar>(i, j) / n3) / log(2);
}
if (dst4.at<uchar>(i, j) != 0)
{
s4 = s4 - (dst4.at<uchar>(i, j) / n4)*log(dst4.at<uchar>(i, j) / n4) / log(2);
}
}
}
//cout << "对比度:" << endl;
//cout << d1 << endl << d2 << endl << d3 << endl << d4 << endl;
ui.textBrowser->insertPlainText(tr("duibidu:\n"));
ui.textBrowser->insertPlainText(tr("%1\n").arg(d1));
ui.textBrowser->insertPlainText(tr("%1\n").arg(d2));
ui.textBrowser->insertPlainText(tr("%1\n").arg(d3));
ui.textBrowser->insertPlainText(tr("%1\n").arg(d4));
ui.textBrowser->moveCursor(QTextCursor::Start);
//cout << "同质性:" << endl;
//cout << t1 << endl << t2 << endl << t3 << endl << t4 << endl;
ui.textBrowser->insertPlainText(tr("tongzhixing:\n"));
ui.textBrowser->insertPlainText(tr("%1\n").arg(t1));
ui.textBrowser->insertPlainText(tr("%1\n").arg(t2));
ui.textBrowser->insertPlainText(tr("%1\n").arg(t3));
ui.textBrowser->insertPlainText(tr("%1\n").arg(t4));
ui.textBrowser->moveCursor(QTextCursor::Start);
//cout << "能量:" << endl;
//cout << e1 << endl << e2 << endl << e3 << endl << e4 << endl;
ui.textBrowser->insertPlainText(tr("nengliang:\n"));
ui.textBrowser->insertPlainText(tr("%1\n").arg(e1));
ui.textBrowser->insertPlainText(tr("%1\n").arg(e2));
ui.textBrowser->insertPlainText(tr("%1\n").arg(e3));
ui.textBrowser->insertPlainText(tr("%1\n").arg(e4));
ui.textBrowser->moveCursor(QTextCursor::Start);
//cout << "熵:" << endl;
//cout << s1 << endl << s2 << endl << s3 << endl << s4 << endl;
ui.textBrowser->insertPlainText(tr("shang:\n"));
ui.textBrowser->insertPlainText(tr("%1\n").arg(s1));
ui.textBrowser->insertPlainText(tr("%1\n").arg(s2));
ui.textBrowser->insertPlainText(tr("%1\n").arg(s3));
ui.textBrowser->insertPlainText(tr("%1\n").arg(s4));
ui.textBrowser->moveCursor(QTextCursor::Start);
}
Qt界面