├── CalcHistograms.m ├── CreateBagOfWords.m ├── ExtractHogPatches.m ├── ImageDownloader.py ├── README.md ├── feature_histogram.m ├── hogPatches.m └── train.m /CalcHistograms.m: -------------------------------------------------------------------------------- 1 | %Author: Jacob Gildenblat, 2014 2 | %Compares the learned Visual Vocabulary and the image training\cross 3 | %calidation set, and computes histogram vectors. 4 | 5 | function [D labels] = CalcHistograms(codebook, blockSize, patchSize, directories, TrainSet, trainSetPercentage) 6 | 7 | %Count the number of total .jpg images that will be used. 8 | %We need this to pre-allocate the histograms for speed. 9 | num = 0; 10 | for i = 1 : length(directories) 11 | directory = char(directories(i)); 12 | num = num + length(dir([directory, '/', '*.jpg'])); 13 | end 14 | 15 | if TrainSet == 1 16 | num = round(num * trainSetPercentage); 17 | else 18 | num = round(num * (1-trainSetPercentage)); 19 | end 20 | 21 | D = zeros(num, size(codebook, 1)); 22 | labels = zeros(num, 1); 23 | 24 | index = 1; 25 | for i = 1 : length(directories) 26 | directory = char(directories(i)); 27 | imagefiles = dir([directory, '/', '*.jpg']); 28 | nfiles = length(imagefiles); % Number of files found 29 | label = (i == 1) * -2 + 1; 30 | 31 | if (TrainSet == 1) 32 | files = 1 : round(nfiles*trainSetPercentage); 33 | else 34 | files = (round(nfiles*trainSetPercentage) + 1) : nfiles; 35 | end 36 | 37 | for ii = files 38 | img = imread([directory ,'/', imagefiles(ii).name]); 39 | if size(img , 1) < 128 || size(img, 2) < 128 40 | continue; 41 | end 42 | patches = ExtractHogPatches(img, patchSize, blockSize); 43 | D(index, : ) = feature_histogram(codebook, patches); 44 | labels(index) = label; 45 | index = index + 1; 46 | end 47 | end 48 | D = D'; 49 | labels = labels'; 50 | end 51 | -------------------------------------------------------------------------------- /CreateBagOfWords.m: -------------------------------------------------------------------------------- 1 | %Author: Jacob Gildenblat, 2014. 2 | %Creates a bag of words from a dataset. 3 | %blockSize is the size of the cells in the HoG descriptors. 4 | %patchSize is the size of the patches. Each patch is used for a HoG 5 | %descriptor. 6 | %directories is a cell array containing two directories with the training 7 | %images. 8 | %trainSetPercentage sets how many images are used for training, and how 9 | %many are used for crosss validation. 10 | function features = CreateBagOfWords(blockSize, patchSize, directories, trainSetPercentage) 11 | 12 | max_size = 10000; 13 | features = zeros(max_size, patchSize * 31); 14 | 15 | index = 1; 16 | for i = 1:length(directories) 17 | directory = char(directories(i)); 18 | imagefiles = dir([directory, '/', '*.jpg']); 19 | nfiles = length(imagefiles); 20 | for ii=1:round(nfiles*trainSetPercentage) 21 | img = imread([directory ,'/', imagefiles(ii).name]); 22 | if (size(img , 1) < patchSize * 2 || size(img, 2) < patchSize * 2) 23 | continue; 24 | end 25 | hogPatches = ExtractHogPatches(img, patchSize, blockSize); 26 | features(index : index + size(hogPatches, 1) - 1 , :) = hogPatches; 27 | index = index + size(hogPatches, 1); 28 | end 29 | end 30 | features = features(1 : index - 1, :); 31 | disp('features size is: ') 32 | size(features') 33 | end 34 | -------------------------------------------------------------------------------- /ExtractHogPatches.m: -------------------------------------------------------------------------------- 1 | %Author: Jacob Gildenblat, 2014 2 | 3 | function patches = ExtractHogPatches(img, patchSize, blockSize) 4 | if (size(img, 3) == 3) 5 | img = single(double(rgb2gray(img))); 6 | else 7 | img = single(double(img)); 8 | end 9 | 10 | [frames] = vl_sift(img); 11 | patches = hogPatches(img, frames', patchSize, blockSize); 12 | end 13 | -------------------------------------------------------------------------------- /ImageDownloader.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | import urllib 5 | from urllib import FancyURLopener 6 | import json 7 | 8 | # Define search term 9 | searchTerm = sys.argv[1] 10 | 11 | # Replace spaces ' ' in search term for '%20' in order to comply with request 12 | searchTerm = searchTerm.replace(' ','%20') 13 | 14 | 15 | # Start FancyURLopener with defined version 16 | class MyOpener(FancyURLopener): 17 | version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11' 18 | myopener = MyOpener() 19 | 20 | # Set count to 0 21 | count= 0 22 | 23 | for i in range(1, 40): 24 | print(count) 25 | # Notice that the start changes for each iteration in order to request a new set of images for each loop 26 | url = ('https://ajax.googleapis.com/ajax/services/search/images?' + 'v=1.0&q='+searchTerm+'&start='+str(i*4)+'&userip=MyIP') 27 | print(url) 28 | 29 | import requests 30 | 31 | results = requests.get(url).json() 32 | print(results) 33 | data = results['responseData'] 34 | if not data: 35 | continue 36 | dataInfo = data['results'] 37 | if dataInfo: 38 | # Iterate for each result and get unescaped url 39 | for myUrl in dataInfo: 40 | count = count + 1 41 | print(myUrl['unescapedUrl']) 42 | 43 | myopener.retrieve(myUrl['unescapedUrl'],str(count+400)+'.jpg') 44 | 45 | # Sleep for one second to prevent IP blocking from Google 46 | time.sleep(1) 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BagOfVisualWords 2 | ================ 3 | 4 | A simple Matlab implementation of Bag Of Words with SIFT keypoints and HoG descriptors, using VLFeat. 5 | -------------------------------------------------------------------------------- /feature_histogram.m: -------------------------------------------------------------------------------- 1 | function h = feature_histogram(codebook, features) 2 | 3 | h = zeros(1, size(codebook, 1)); 4 | 5 | %This can be used for hard value comparing. 6 | % for i = 1 : size(features, 1) 7 | % patch = features(i, :); 8 | % [m idx] = min(sum(((codebook - repmat(patch, size(codebook, 1), 1)).^2)')'); 9 | % h(idx) = h(idx) + 1; 10 | % end 11 | % h = h / sum(sum(h)); 12 | 13 | %Soft values in the histogram: 14 | sigma = 0.2; 15 | for i = 1 : size(features, 1) 16 | for j = 1 : size(codebook, 1) 17 | feature = features(i, :); 18 | word = codebook(j, :); 19 | h(j) = h(j) + exp(-sum( (word - feature).^2 ) / (2*sigma^2)); 20 | end 21 | end 22 | h = h / sum(sum(h)); 23 | 24 | 25 | end 26 | -------------------------------------------------------------------------------- /hogPatches.m: -------------------------------------------------------------------------------- 1 | function hog_patches = hogPatches(img, frames, patchSize, blockSize) 2 | 3 | hog_patches = []; 4 | 5 | if size(img, 1) <= patchSize || size(img, 2) <= patchSize 6 | img = imresize(img, [256 256]); 7 | end 8 | 9 | for f = frames 10 | x = round(f(1)); y = round(f(2)); 11 | x = min(max(x, patchSize), size(img, 1) - patchSize); 12 | y = min(max(y, patchSize), size(img, 2) - patchSize); 13 | 14 | patch = img( x - patchSize/2 : x + patchSize/2, y - patchSize/2 : y + patchSize/2); 15 | hog = vl_hog(patch, blockSize); 16 | hog = reshape(hog, 1, []); 17 | hog_patches = [hog_patches ; hog]; 18 | end 19 | 20 | end -------------------------------------------------------------------------------- /train.m: -------------------------------------------------------------------------------- 1 | blockSize = 8; 2 | patchSize = 64; 3 | directories = {'mac' , 'win'}; 4 | 5 | disp('Collecting features from dataset.. ') 6 | features = CreateBagOfWords(blockSize, patchSize, directories, 0.8); 7 | 8 | disp('Features collected, clustering.. ') 9 | [codebook, assignments] = vl_kmeans(features', 80, 'Initialization', 'plusplus'); 10 | 11 | disp('Comparing dataset to codebook.. ') 12 | [X Y] = CalcHistograms(codebook', blockSize, patchSize, directories, 1, 0.8); 13 | 14 | disp('Training SVM classifier.. ') 15 | [W B] = vl_svmtrain(X, double(Y), 0.02); 16 | 17 | disp('Success rate on train set: ') 18 | sum(sign(W' * X + B) == Y) / length(Y) 19 | 20 | [CROSS_VALID_SET CROSS_VALID_LABELS] = CalcHistograms(codebook', blockSize, patchSize, directories, 0, 0.8); 21 | disp('Success rate on cross validation set: ') 22 | sum(sign(W' * CROSS_VALID_SET + B) == CROSS_VALID_LABELS) / length(CROSS_VALID_LABELS) 23 | --------------------------------------------------------------------------------