基于KNN的圖像分類

實(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ì)算。

image.png

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

image.png

將每個(gè)訓(xùn)練集的內(nèi)容以二進(jìn)制的形式讀到temp中。

2.再對(duì)訓(xùn)練集中的每張圖片讀入:

image.png

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

image.png

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

image.png

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

image.png

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

image.png

K=1

image.png

K=2


image.png

K=3

image.png

K=4

image.png

K=5

image.png

K=6

image.png

K=7

image.png

K=8

image.png

K=9

image.png

繪制成曲線圖:

image.png

實(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;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容