由void readDataset(string imagesFile, string labelsFile, vector<Mat>& images, vector<int>& labels) void convolve(Mat& input, Mat filter, Mat& output) void pool(Mat& input, Mat& output) void fullyConnected(Mat& input, Mat& weight, Mat& bias, Mat& output) void softmax(Mat& input, Mat& output) void cnnModel(Mat& input, Mat& output)组成的C++手写数字识别main函数实现
时间: 2024-03-07 18:48:03 浏览: 89
好的,以下是一个简单的手写数字识别的C++程序实现:
```c++
#include <iostream>
#include <fstream>
#include <vector>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// 读取MNIST数据集
void readDataset(string imagesFile, string labelsFile, vector<Mat>& images, vector<int>& labels)
{
ifstream ifsImages(imagesFile, ios::binary);
ifstream ifsLabels(labelsFile, ios::binary);
if (!ifsImages.is_open() || !ifsLabels.is_open()) {
cout << "Failed to open file." << endl;
return;
}
int magicImages, magicLabels, numImages, numLabels;
ifsImages.read((char*)&magicImages, sizeof(magicImages));
ifsLabels.read((char*)&magicLabels, sizeof(magicLabels));
ifsImages.read((char*)&numImages, sizeof(numImages));
ifsLabels.read((char*)&numLabels, sizeof(numLabels));
magicImages = reverseInt(magicImages);
magicLabels = reverseInt(magicLabels);
numImages = reverseInt(numImages);
numLabels = reverseInt(numLabels);
for (int i = 0; i < numImages; ++i) {
Mat image = Mat::zeros(28, 28, CV_8UC1);
for (int r = 0; r < 28; ++r) {
for (int c = 0; c < 28; ++c) {
unsigned char pixel;
ifsImages.read((char*)&pixel, sizeof(pixel));
image.at<uchar>(r, c) = pixel;
}
}
images.push_back(image);
}
for (int i = 0; i < numLabels; ++i) {
unsigned char label;
ifsLabels.read((char*)&label, sizeof(label));
labels.push_back((int)label);
}
}
// 卷积操作
void convolve(Mat& input, Mat filter, Mat& output)
{
int filterSize = filter.rows;
int pad = filterSize / 2;
Mat paddedInput;
copyMakeBorder(input, paddedInput, pad, pad, pad, pad, BORDER_CONSTANT, Scalar(0));
output.create(input.rows, input.cols, input.type());
for (int r = pad; r < paddedInput.rows - pad; ++r) {
for (int c = pad; c < paddedInput.cols - pad; ++c) {
double sum = 0.0;
for (int fr = 0; fr < filterSize; ++fr) {
for (int fc = 0; fc < filterSize; ++fc) {
int ir = r - pad + fr;
int ic = c - pad + fc;
sum += paddedInput.at<double>(ir, ic) * filter.at<double>(fr, fc);
}
}
output.at<double>(r - pad, c - pad) = sum;
}
}
}
// 池化操作
void pool(Mat& input, Mat& output)
{
output.create(input.rows / 2, input.cols / 2, input.type());
for (int r = 0; r < input.rows; r += 2) {
for (int c = 0; c < input.cols; c += 2) {
double maxVal = 0.0;
for (int pr = 0; pr < 2; ++pr) {
for (int pc = 0; pc < 2; ++pc) {
double val = input.at<double>(r + pr, c + pc);
if (val > maxVal) {
maxVal = val;
}
}
}
output.at<double>(r / 2, c / 2) = maxVal;
}
}
}
// 全连接层操作
void fullyConnected(Mat& input, Mat& weight, Mat& bias, Mat& output)
{
output.create(1, weight.cols, CV_64FC1);
for (int c = 0; c < weight.cols; ++c) {
double sum = 0.0;
for (int r = 0; r < weight.rows; ++r) {
sum += input.at<double>(r) * weight.at<double>(r, c);
}
sum += bias.at<double>(0, c);
output.at<double>(0, c) = sum;
}
}
// Softmax操作
void softmax(Mat& input, Mat& output)
{
output.create(1, input.cols, CV_64FC1);
double sum = 0.0;
for (int c = 0; c < input.cols; ++c) {
double expVal = exp(input.at<double>(0, c));
output.at<double>(0, c) = expVal;
sum += expVal;
}
for (int c = 0; c < input.cols; ++c) {
output.at<double>(0, c) /= sum;
}
}
// CNN模型
void cnnModel(Mat& input, Mat& output)
{
// 卷积层1
Mat filter1 = (Mat_<double>(5, 5) << -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,24,24,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1);
Mat conv1;
convolve(input, filter1, conv1);
// 激活函数ReLU
Mat relu1;
cv::max(0, conv1, relu1);
// 池化层1
Mat pool1;
pool(relu1, pool1);
// 卷积层2
Mat filter2 = (Mat_<double>(5, 5) << -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,24,24,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1);
Mat conv2;
convolve(pool1, filter2, conv2);
// 激活函数ReLU
Mat relu2;
cv::max(0, conv2, relu2);
// 池化层2
Mat pool2;
pool(relu2, pool2);
// 全连接层1
Mat fcInput = pool2.reshape(1, 1);
Mat weight1 = (Mat_<double>(fcInput.cols, 128) << ...);
Mat bias1 = (Mat_<double>(1, 128) << ...);
Mat fc1;
fullyConnected(fcInput, weight1, bias1, fc1);
// 激活函数ReLU
Mat relu3;
cv::max(0, fc1, relu3);
// 全连接层2
Mat weight2 = (Mat_<double>(relu3.cols, 10) << ...);
Mat bias2 = (Mat_<double>(1, 10) << ...);
Mat fc2;
fullyConnected(relu3, weight2, bias2, fc2);
// Softmax
softmax(fc2, output);
}
int main()
{
// 读取MNIST数据集
vector<Mat> images;
vector<int> labels;
readDataset("train-images-idx3-ubyte", "train-labels-idx1-ubyte", images, labels);
// 训练CNN模型
for (int i = 0; i < images.size(); ++i) {
Mat input = images[i] / 255.0;
Mat output;
cnnModel(input, output);
// 计算损失函数
double loss = 0.0;
for (int c = 0; c < output.cols; ++c) {
int label = (c == labels[i]) ? 1 : 0;
loss += -label * log(output.at<double>(0, c));
}
// 反向传播更新权重和偏置
// ...
}
return 0;
}
```
需要注意的是,这只是一个简单的手写数字识别程序实现,具体的实现细节还需要根据实际需求进行调整和完善。
阅读全文