OpenCV - 人工神经网络ANN的实现以及图像分割

人工神经网络(artificial neural network)可谓玄乎,这边也不做一个详细解释。那大概是个什么工作原理呢?经常可以看见神经网络的网络图,每一层都有很多圈圈,那这些圈圈是什么呢?

人工神经网络每一层都指的是特征,层数不同,特征的深度也就不同。比如第一层2个圈,即2个输入那就是样本有两个特征作为输入,到了第二层有3个圈了,那就是前面一层的2个特征根据不同的权重组合成了这3个特征。最后输出层的个数即为我们需要分类数,输出的值为属于每一个类别的概率。


opencv中人工神经网络要控制的参数也就是层数和每层的特征数。

1、需要注意的是这边预测得到的该样本属于每个标签的概率,挑选概率最大。所以response的大小应该为1x标签数

2、上面的第一种转换的是独热编码的形式,即下面程序中的形式。但是如果不用独热编码的形式输出,那输出层只有一个特征,可以根据概率值的大小来判断是否属于该标签

// ex12.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <opencv2\opencv.hpp>

using namespace std;
using namespace cv;
using namespace cv::ml;

int train_sample_nums = 200;

int main()
{
	/******************数据集制作***************************/
	Mat trainData(train_sample_nums, 2, CV_32FC1);
	Mat trainClassess(train_sample_nums, 1, CV_32SC1);               //注意标签的格式,有符号

	//创建可视化图像
	Mat img(500, 500, CV_8UC3, Scalar::all(0));
	//样本点
	Mat sample(1, 2, CV_32FC1);

	Mat trainData1, trainData2, trainClasses1, trainClasses2;

	RNG rng = RNG(-1);
	//生成均值为(200,200),方差为(40,40)的随机数据
	trainData1 = trainData.rowRange(0, train_sample_nums / 2);
	rng.fill(trainData1, CV_RAND_NORMAL, Scalar(200, 200), Scalar(40, 40));
	trainData2 = trainData.rowRange(train_sample_nums / 2, train_sample_nums);
	rng.fill(trainData2, CV_RAND_NORMAL, Scalar(300, 300), Scalar(40, 40));

	//trainClasses1和trainClassess的前100行绑定
	trainClasses1 = trainClassess.rowRange(0, train_sample_nums / 2);
	trainClasses1 = Scalar::all(0);
	trainClasses2 = trainClassess.rowRange(train_sample_nums / 2, train_sample_nums);
	trainClasses2 = Scalar::all(1);


	cv::Ptr<cv::ml::ANN_MLP> ann = cv::ml::ANN_MLP::create();

	int nlayers = 4; //隐藏层节点数量,即隐藏的特征数量
	int numCharacters = 2; //输出层特征数量
	Mat layers(1, 4, CV_32SC1);
	layers.at<int>(0, 0) = trainData.cols; //输入层特征数量
	layers.at<int>(0, 1) = nlayers;
	layers.at<int>(0, 2) = 4;
	layers.at<int>(0, 3) = 2;             //这边输出层的特征数量是要和response_mat挂钩


	ann->setLayerSizes(layers);
	ann->setActivationFunction(cv::ml::ANN_MLP::SIGMOID_SYM);
	ann->setTrainMethod(cv::ml::ANN_MLP::BACKPROP, 0.1, 0.1);
	ann->setTermCriteria(cv::TermCriteria(TermCriteria::MAX_ITER, 1000, 1e-6));

	Mat trainClasses_onehot(train_sample_nums, numCharacters, CV_32FC1);  //转化为独热编码的形式
	for (int i = 0; i < trainClasses_onehot.rows; i++)
		for (int j = 0; j < trainClasses_onehot.cols; j++)
		{
			if (trainClassess.at<int>(i, 0) == j)    //那样本的分类应该为0,1,2,3,4之类的
				trainClasses_onehot.at<float>(i, j) = 1;
			else
				trainClasses_onehot.at<float>(i, j) = 0;
		}

	cv::Ptr<TrainData> TrainData = TrainData::create(trainData, ROW_SAMPLE, trainClasses_onehot);
	ann->train(TrainData);

	for (int i = 0; i < img.rows; i++)
		for (int j = 0; j < img.cols; j++)
		{
			Mat sample_mat = (Mat_<float>(1, 2) << i, j);
			Mat response_mat(1, 2, CV_32FC1);
			ann->predict(sample_mat, response_mat);
			Point maxLoc;
			double maxval;
			minMaxLoc(response_mat, 0, &maxval, 0, &maxLoc);
			if (maxLoc.x == 0)
				img.at<Vec3b>(i, j) = Vec3b(0, 255, 0);
			else if (maxLoc.x == 1)
				img.at<Vec3b>(i, j) = Vec3b(255, 0, 0);
			/*
			对应输出层为1的response
			float response = response_mat.ptr<float>(0)[0];
			if (response > 0.5)
				img.at<Vec3b>(i, j) = Vec3b(0, 255, 0);
			else if (response < 0.5)
				img.at<Vec3b>(i, j) = Vec3b(255, 0, 0);
			*/
		}


	for (int i = 0; i < train_sample_nums / 2; i++)
	{
		Point pt;
		pt.x = round(trainData1.at<float>(i, 0));
		pt.y = round(trainData1.at<float>(i, 1));
		circle(img, pt, 1, Scalar(0, 255, 255));

		pt.x = round(trainData2.at<float>(i, 0));
		pt.y = round(trainData2.at<float>(i, 1));
		circle(img, pt, 1, Scalar(255, 255, 0));
	}

	waitKey(0);
}



图像分割待填坑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值