實(shí)驗(yàn)要求
對(duì)于測(cè)試集中的每一幅圖像,計(jì)算其與訓(xùn)練集的所有圖像的距離,并挑選出前K的最近的圖像,根據(jù)他們的類別在判斷測(cè)試集中的每一幅圖像的類別。最后輸出這200幅圖像的準(zhǔn)確率。
實(shí)驗(yàn)過(guò)程及結(jié)果
我做實(shí)驗(yàn)的時(shí)候是將car和bird分開讀取和分開計(jì)算,所以下面的步驟中都是car和bird分開的操作的,我只截取一個(gè)類型的(car或者bird)。
因?yàn)槊總€(gè)圖片的大小具體不太一樣,我就取了讀取一個(gè)圖片1000個(gè)字節(jié)進(jìn)行計(jì)算
1.需要將圖片用二進(jìn)制讀入
查看jpg文件的格式,可以看到26FH開始才是圖片的信息,所以我們判斷的時(shí)候也從26FH開始計(jì)算。

Knn的值我們采取的是歐式距離,關(guān)鍵代碼:

將每個(gè)訓(xùn)練集的內(nèi)容以二進(jìn)制的形式讀到temp中。
2.再對(duì)訓(xùn)練集中的每張圖片讀入:

3.計(jì)算歐式距離:

4.將計(jì)算的歐式距離的k最小的值以及判斷的類型存儲(chǔ)

5.最后遍歷判斷的類型與真是圖像的類型并統(tǒng)計(jì):

6.最后計(jì)算準(zhǔn)確率:

K=1

K=2

K=3

K=4

K=5

K=6

K=7

K=8

K=9

繪制成曲線圖:

實(shí)驗(yàn)總結(jié)**
可以看到,隨著k的增大,bird的識(shí)別率逐漸增高,car的卻逐漸減小,整體趨于穩(wěn)定,我認(rèn)為造成這樣的原因的可能是設(shè)置的讀取1000個(gè)字節(jié)可能對(duì)car不利。但是通過(guò)010edit來(lái)看,car圖片的大小整體比bird更大,所以1000個(gè)字節(jié)更接近c(diǎn)ar的圖片,但奇怪的是car的識(shí)別率卻低。這一部分還需要再考慮考慮。
knn.h代碼:
#pragma once
#include <string>
using namespace std;
class knnmodel
{
public:
knnmodel();
~knnmodel();
int InitTypeK(char _type, int _k);
int readtestjpg(string filename);//讀入一個(gè)測(cè)試的圖片
char knn(); //計(jì)算knn,并且返回判斷的類型
private:
char type; //圖片本身的類型,car 或者 bird
int k; //knn中的k,K個(gè)最相近的圖像
int size= 1000; //圖片的大小
char* pbuf; //存儲(chǔ)圖片的二進(jìn)制信息
};
zjx_KNN.cpp代碼:
#include "knn.h"
#include <fstream>
#include<iostream>
#include <windows.h>
knnmodel::knnmodel()
{
/*this->type = _type;
this->k = _k;*/
}
knnmodel::~knnmodel()
{
}
int knnmodel::InitTypeK(char _type,int _k)
{
this->type = _type;
this->k = _k;
return 0;
}
int knnmodel::readtestjpg(string filename)
{
ifstream inFile(filename, ios::in | ios::binary);
if (!inFile.is_open()) {
cout << "open error" << endl;
return 1;
}
pbuf = new char[size];
inFile.read(pbuf, size);
inFile.close();
return 0;
}
char knnmodel::knn()
{
char* temp = new char[size];
char* temp1 = new char[size];
double* knn_num = new double[k]();//存儲(chǔ)前k個(gè)最大knn值
char* KnnType = new char[k];//存儲(chǔ)前k個(gè)最大knn值的類型
double KnnSum = 0; //計(jì)算每次knn的值
string CarPicture = "D:\\dataset\\traincar\\(";
string BirdPicture = "D:\\dataset\\trainbird\\(";
for (int i = 1; i <= 1000; i++)
{
string CarName = CarPicture + to_string(i) + ").jpg";//每次需要讀取的樣本集的名字
ifstream inFile(CarName, ios::in | ios::binary);
if (!inFile.is_open()) {
cout << "open error" << endl;
return 0;
}
inFile.read(temp, size);
inFile.close();
KnnSum = 0;
for (int j = 623; j < size; j++)
{
KnnSum += (temp[j]-pbuf[j])*(temp[j] - pbuf[j]);
}
for (int ki = 0; ki < k; ki++)
{
if (knn_num[ki] == 0)
{
knn_num[ki] = KnnSum;
KnnType[ki] = 'c';
break;
}
else if (KnnSum < knn_num[ki])
{
knn_num[ki] = KnnSum;
KnnType[ki] = 'c';
break;
}
}
}
for (int i = 1; i <= 1000; i++)
{
string BirdName = BirdPicture + to_string(i) + ").jpg";//每次需要讀取的樣本集的名字
ifstream inFile(BirdName, ios::in | ios::binary);
if (!inFile.is_open()) {
cout << "open error" << endl;
return 0;
}
inFile.read(temp1, size);
inFile.close();
KnnSum = 0;
for (int j = 623; j < size; j++)
{
KnnSum += pow(temp1[j] - pbuf[j], 2);
}
for (int ki = 0; ki < k; ki++)
{
if (knn_num[ki] == 0)
{
knn_num[ki] = KnnSum;
KnnType[ki] = 'b';
break;
}
else if (KnnSum < knn_num[ki])
{
knn_num[ki] = KnnSum;
KnnType[ki] = 'b';
break;
}
}
}
cout << "*********************************************************************************************" << endl;
int BirdNum = 0,CarNum=0;
for (int i = 0; i < k; i++)
{
cout << "KNN的計(jì)算值:"<<knn_num[i] << "\t" <<"判斷的類型:"<< KnnType[i] << endl;
}
//計(jì)算判斷為c的數(shù)量和判斷為b的數(shù)量
for (int i = 0; i < k; i++)
{
if (KnnType[i] == 'c')
{
CarNum++;
}
else if (KnnType[i] == 'b')
{
BirdNum++;
}
}
if (CarNum >= BirdNum)
return 'c';
else
return 'b';
}
main.cpp
#include<iostream>
#include "knn.h"
#define TOTALNUM 200
int main()
{
int CorrectBird = 0;
int CorrectCar = 0;
knnmodel* testbird = new knnmodel[101];
knnmodel* testcar = new knnmodel[101];
string TestBirdFile = "D:\\dataset\\testbird\\(";
string TestCarFile = "D:\\dataset\\testcar\\ (";
char* BirdResult = new char[101];
char* CarResult = new char[101];
//計(jì)算bird圖像的判斷結(jié)果
for (int i = 1; i <= 100; i++)
{
testbird[i].InitTypeK('b', 9);
string RealTestName = TestBirdFile + to_string(i) + ").jpg";
testbird[i].readtestjpg(RealTestName);
BirdResult[i] = testbird[i].knn();
cout << "第" << i << "張bird圖片判斷為" << BirdResult[i] << endl;
}
//計(jì)算bird圖像的判斷結(jié)果
for (int i = 1; i <= 100; i++)
{
testcar[i].InitTypeK('b', 9);
string RealTestName = TestCarFile + to_string(i) + ").jpg";
testcar[i].readtestjpg(RealTestName);
CarResult[i] = testcar[i].knn();
cout << "第" << i << "張car圖片判斷為" << CarResult[i] << endl;
}
for (int i = 1; i < 101; i++)
{
if (BirdResult[i] == 'b')
CorrectBird++;
else if (CarResult[i] == 'c')
CorrectCar++;
}
cout << "************************************" << endl;
cout << endl;
cout << "Bird圖片判斷正確的有" << CorrectBird << "幅,Car判斷正確的有" << CorrectCar << "幅"<<endl;
cout << "200幅圖片種有" << CorrectBird + CorrectCar << "幅,正確率為" << double(CorrectBird + CorrectCar) / 200 << endl;
return 0;
}