├── img ├── Bckg.jpg ├── Body.jpg ├── Face.jpg ├── Torso.jpg └── Bounding-box.jpg ├── README.md └── src ├── checkBox.lua └── makeClasses.lua /img/Bckg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atcold/torch-INRIA/master/img/Bckg.jpg -------------------------------------------------------------------------------- /img/Body.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atcold/torch-INRIA/master/img/Body.jpg -------------------------------------------------------------------------------- /img/Face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atcold/torch-INRIA/master/img/Face.jpg -------------------------------------------------------------------------------- /img/Torso.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atcold/torch-INRIA/master/img/Torso.jpg -------------------------------------------------------------------------------- /img/Bounding-box.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atcold/torch-INRIA/master/img/Bounding-box.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # torch-INRIA 2 | 3 | [`makeClasses`](src/makeClasses.lua) is a simple script that loads face, torso, body and background samples from INRIA dataset and saves them in a *ImageNet* compatible format. This means, object are fairly centred and the sample size is 256 × 256 px². 4 | 5 | In this first release, the dataset has to be downloaded manually from [here](http://pascal.inrialpes.fr/data/human/INRIAPerson.tar) and extracted into `~/Work/Datasets`. 6 | 7 | > In the code there is my user name (`~` = `/Users/atcold`). I will probably update it in a following commit. 8 | 9 | What this script does is simply extract every *face*, *torso* and *body* from the positive and *background* from the negative folder, cropping them square and saving them into a `Extracted-data` folder, under a sub-directory representing their label. 10 | 11 | - `Face`: are sized 1/3 of the width of the bounding box; 12 | - `Torso`: upper biggest square croppable from the bounding box; 13 | - `Body`: square with side equal to the hight of the bounding box. If the limits of the image are exceeded (the image is too narrow), the first/last column of pixel is replicated to fill the gap; 14 | - `Bckg`: squares of 128 px are cropped randomly from the negative samples. 15 | 16 | And this is how they look like 17 | 18 | ![Face](img/Face.jpg) 19 | ![Torso](img/Torso.jpg) 20 | ![Body](img/Body.jpg) 21 | ![Bckg](img/Bckg.jpg) 22 | 23 | ## How to run it 24 | After changing the folder pointers in the code (which I will make soon automatic), in the [`src`](src) directory, run 25 | 26 | ``` 27 | th makeClasses.lua 28 | ``` 29 | 30 | ## How is this done? 31 | To have an idea of the information provided with the dataset, I wrote [`checkBox`](src/checkBox.lua) which gives a general idea of what we can do with the data. To run it, go to the [`src`](src) directory and type 32 | 33 | ``` 34 | qlua checkBox.lua 35 | ``` 36 | 37 | ![Bounding-box](img/Bounding-box.jpg) 38 | -------------------------------------------------------------------------------- /src/checkBox.lua: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- Check the position of a bounding box 3 | -------------------------------------------------------------------------------- 4 | -- Alfredo Canziani, Jul 14 5 | -------------------------------------------------------------------------------- 6 | 7 | -- Requires -------------------------------------------------------------------- 8 | require 'image' 9 | require 'qtwidget' 10 | 11 | -- Main script------------------------------------------------------------------ 12 | -- Load image 13 | img = image.load('/Users/atcold/Work/Datasets/INRIAPerson/Train/pos/crop001001.png') 14 | 15 | -- Annotation format 16 | --[[ 17 | Original label for object 1 "PASperson" : "UprightPerson" 18 | Center point on object 1 "PASperson" (X, Y) : (396, 185) 19 | Bounding box for object 1 "PASperson" (Xmin, Ymin) - (Xmax, Ymax) : (261, 109) - (511, 705) 20 | --]] 21 | 22 | -- Create list box centres 23 | boxCentre = {} 24 | table.insert(boxCentre, {x = 396, y = 185}) 25 | table.insert(boxCentre, {x = 119, y = 385}) 26 | table.insert(boxCentre, {x = 219, y = 235}) 27 | 28 | -- Create list box coordinates 29 | boundingBox = {} 30 | table.insert(boundingBox, {xMin = 261, yMin = 109, xMax = 511, yMax = 705}) 31 | table.insert(boundingBox, {xMin = 31, yMin = 326, xMax = 209, yMax = 712}) 32 | table.insert(boundingBox, {xMin = 148, yMin = 179, xMax = 290, yMax = 641}) 33 | 34 | for _,b in ipairs(boundingBox) do 35 | b.x = b.xMin 36 | b.y = b.yMin 37 | b.w = b.xMax - b.xMin + 1 38 | b.h = b.yMax - b.yMin + 1 39 | end 40 | 41 | -- Display image and get handle 42 | win = qtwidget.newwindow(img:size(3), img:size(2)) 43 | image.display{image = img, win = win} 44 | 45 | -- Display box centres 46 | win:setcolor(1,0,0) 47 | win:arc(boxCentre[1].x, boxCentre[1].y, 5, 0, 360) 48 | win:fill() 49 | win:rectangle(boundingBox[1].x, boundingBox[1].y, boundingBox[1].w, boundingBox[1].h) 50 | win:stroke() 51 | 52 | win:setcolor(0,1,0) 53 | win:arc(boxCentre[2].x, boxCentre[2].y, 5, 0, 360) 54 | win:fill() 55 | win:rectangle(boundingBox[2].x, boundingBox[2].y, boundingBox[2].w, boundingBox[2].h) 56 | win:stroke() 57 | 58 | win:setcolor(0,0,1) 59 | win:arc(boxCentre[3].x, boxCentre[3].y, 5, 0, 360) 60 | win:fill() 61 | win:rectangle(boundingBox[3].x, boundingBox[3].y, boundingBox[3].w, boundingBox[3].h) 62 | win:stroke() 63 | 64 | -- Extract torso 65 | for nbBox, box in ipairs(boundingBox) do 66 | torso = img[{ {},{box.yMin,box.yMin+box.w},{box.xMin,box.xMax} }] 67 | --print(#torso) 68 | image.display{image=image.scale(torso,256,256),legend='Torso'} 69 | end 70 | 71 | -- Extract face (w/3) 72 | for nbBox, box in ipairs(boxCentre) do 73 | factor = boundingBox[nbBox].w / 3 74 | delta = math.floor(factor/2) 75 | face = img[{ {},{box.y - delta, box.y + delta},{box.x - delta,box.x + delta} }] 76 | --print(#face) 77 | image.display{image=image.scale(face,256,256),legend='Face'} 78 | end 79 | 80 | -- Extract body 81 | imgW = img:size(3) 82 | imgH = img:size(2) 83 | for nbBox, box in ipairs(boundingBox) do 84 | bodyRect = img[{ {},{box.yMin,box.yMax},{box.xMin,box.xMax} }] 85 | --image.display(bodyRect) 86 | x0 = math.floor(box.x + box.w/2 - box.h/2) 87 | x1 = math.floor(box.x + box.w/2 + box.h/2) - 1 88 | x0crop = x0 > 0 and x0 or 1 89 | x1crop = x1 > imgW and imgW or x1 90 | 91 | bodyCrop = img[{ {},{box.yMin,box.yMax},{x0crop,x1crop} }] 92 | --image.display(bodyCrop) 93 | 94 | body = torch.Tensor(3,box.h,box.h) 95 | if x0 < 0 then 96 | x0 = x0 - 1 97 | for i = 1,-x0 do 98 | body[{ {},{},i }] = img[{ {},{box.yMin,box.yMax},1 }] 99 | end 100 | else x0 = 0 end 101 | --print(#bodyCrop,x0) 102 | body[{ {},{},{1-x0,bodyCrop:size(3)-x0} }] = bodyCrop 103 | if x1 > imgW then 104 | for i = box.h-(x1-imgW),box.h do 105 | body[{ {},{},i }] = img[{ {},{box.yMin,box.yMax},imgW }] 106 | end 107 | end 108 | 109 | image.display{image=image.scale(body,256,256),legend='Body'} 110 | end 111 | -------------------------------------------------------------------------------- /src/makeClasses.lua: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- Generate face, torso, person and backgroud classes 3 | -- (for a total of 1237 bounding boxes) 4 | -------------------------------------------------------------------------------- 5 | -- Alfredo Canziani, Jul/Aug 14 6 | -------------------------------------------------------------------------------- 7 | 8 | -- Requires -------------------------------------------------------------------- 9 | require 'sys' 10 | require 'image' 11 | 12 | -- Main script------------------------------------------------------------------ 13 | extractedPath = 'Extracted-data' 14 | if paths.dirp(extractedPath) then 15 | error('Destination folder already existing') 16 | end 17 | datasets = {'Train', 'Test'} 18 | 19 | for _, dataset in ipairs(datasets) do 20 | 21 | print(sys.COLORS.blue .. ' > Building ' .. dataset .. ' directory tree') 22 | 23 | torsoPath = extractedPath .. '/' .. dataset .. '/Torso/' 24 | facePath = extractedPath .. '/' .. dataset .. '/Face/' 25 | bodyPath = extractedPath .. '/' .. dataset .. '/Body/' 26 | bckgPath = extractedPath .. '/' .. dataset .. '/Bckg/' 27 | os.execute('mkdir -p ' .. torsoPath) 28 | os.execute('mkdir -p ' .. facePath) 29 | os.execute('mkdir -p ' .. bodyPath) 30 | os.execute('mkdir -p ' .. bckgPath) 31 | 32 | print(sys.COLORS.green .. ' > + Extracting positive ' .. dataset .. 'ing examples') 33 | 34 | annPath = '/Users/atcold/Work/Datasets/INRIAPerson/' .. dataset .. '/annotations/' 35 | for skip, annotation in ipairs(sys.split(sys.ls(annPath),'\n')) do 36 | 37 | -- Gets lines of bounding box coorinates 38 | grepPath = '/Users/atcold/Work/Datasets/INRIAPerson/' .. dataset .. '/annotations/' 39 | grep = sys.execute('grep "Bounding" ' .. grepPath .. annotation) 40 | -- Split lines 41 | grepSplit = sys.split(grep,'\n') 42 | -- Extract box coordinates 43 | --[[ 44 | Format: 45 | > Bounding box for object 1 "PASperson" (Xmin, Ymin) - (Xmax, Ymax) : (261, 109) - (511, 705) 46 | --]] 47 | boundingBox = {} 48 | for _,b in ipairs(grepSplit) do 49 | xMin, yMin, xMax, yMax = string.match(b,'(%d+), (%d+)%) %- %((%d+), (%d+)') 50 | table.insert(boundingBox, { 51 | xMin = tonumber(xMin), 52 | yMin = tonumber(yMin), 53 | xMax = tonumber(xMax), 54 | yMax = tonumber(yMax) 55 | }) 56 | box = boundingBox[#boundingBox] 57 | box.xMin = box.xMin > 0 and box.xMin or 1 -- mixed coordinate 0/1 58 | box.yMin = box.yMin > 0 and box.yMin or 1 59 | box.x = box.xMin 60 | box.y = box.yMin 61 | box.w = box.xMax - box.xMin + 1 62 | box.h = box.yMax - box.yMin + 1 63 | end 64 | 65 | -- Get lines of face centre 66 | grep = sys.execute('grep "on object" ' .. grepPath .. annotation) 67 | -- Split lines 68 | grepSplit = sys.split(grep,'\n') 69 | -- Extract faces centre 70 | --[[ 71 | Format: 72 | > Center point on object 1 "PASperson" (X, Y) : (396, 185) 73 | --]] 74 | boxCentre = {} 75 | for _,b in ipairs(grepSplit) do 76 | x, y = string.match(b,'(%d+), (%d+)') 77 | table.insert(boxCentre, { 78 | x = tonumber(x), 79 | y = tonumber(y) 80 | }) 81 | end 82 | 83 | -- Load image 84 | --[[ 85 | Format: 86 | > Image filename : "Train/pos/crop001001.png" 87 | --]] 88 | grep = sys.execute('grep "filename" ' .. grepPath .. annotation) 89 | fileName = string.match(grep,'"(.+)"') 90 | img = image.load('/Users/atcold/Work/Datasets/INRIAPerson/' .. fileName) 91 | imgW = img:size(3) 92 | imgH = img:size(2) 93 | fileName = string.match(fileName,'pos/(.+)%.') .. '-' 94 | 95 | -- Extract torso 96 | for nbBox, box in ipairs(boundingBox) do 97 | torso = img[{ {},{box.yMin,box.yMin+box.w},{box.xMin,box.xMax} }] 98 | --print(#torso) 99 | --image.display{image=image.scale(torso,256,256),legend='Torso'} 100 | image.savePNG(torsoPath .. fileName .. nbBox .. '.png', image.scale(torso,256,256)) 101 | end 102 | 103 | -- Extract face (w/3) 104 | for nbBox, box in ipairs(boxCentre) do 105 | factor = boundingBox[nbBox].w / 3 106 | delta = math.floor(factor/2) 107 | --if box.y - delta < 1 then print(box.y,delta,annotation) end 108 | yBug = box.y - delta > 1 and box.y - delta or 1 -- for just 2 annoying images 109 | face = img[{ {},{yBug, box.y + delta},{box.x - delta,box.x + delta} }] 110 | --print(#face) 111 | --image.display{image=image.scale(face,256,256),legend='Face'} 112 | image.savePNG(facePath .. fileName .. nbBox .. '.png', image.scale(face,256,256)) 113 | end 114 | 115 | -- Extract body 116 | for nbBox, box in ipairs(boundingBox) do 117 | bodyRect = img[{ {},{box.yMin,box.yMax},{box.xMin,box.xMax} }] 118 | --image.display(bodyRect) 119 | x0 = math.floor(box.x + box.w/2 - box.h/2) 120 | x1 = math.floor(box.x + box.w/2 + box.h/2 - 1) 121 | x0crop = x0 > 0 and x0 or 1 122 | x1crop = x1 > imgW and imgW or x1 123 | 124 | bodyCrop = img[{ {},{box.yMin,box.yMax},{x0crop,x1crop} }] 125 | --image.display(bodyCrop) 126 | 127 | body = torch.Tensor(3,box.h,box.h) 128 | if x0 < 0 then 129 | x0 = x0 - 1 130 | for i = 1,-x0 do 131 | body[{ {},{},i }] = img[{ {},{box.yMin,box.yMax},1 }] 132 | end 133 | else x0 = 0 end 134 | --print(#bodyCrop,x0) 135 | body[{ {},{},{1-x0,bodyCrop:size(3)-x0} }] = bodyCrop 136 | if x1 > imgW then 137 | for i = box.h-(x1-imgW),box.h do 138 | body[{ {},{},i }] = img[{ {},{box.yMin,box.yMax},imgW }] 139 | end 140 | end 141 | 142 | --image.display{image=image.scale(body,256,256),legend='Body'} 143 | image.savePNG(bodyPath .. fileName .. nbBox .. '.png', image.scale(body,256,256)) 144 | end 145 | 146 | collectgarbage() 147 | 148 | end 149 | 150 | print(sys.COLORS.green .. ' > + Extracting negative (background) ' .. dataset .. 'ing examples') 151 | 152 | -- Training set 153 | -- > There are 1237 bounding box, 1218 bckg images 154 | -- > we need (1237 - 1218 =) 19 more bckg crops 155 | -- Testing set 156 | -- > There are 589 bounding box, 453 bckg images 157 | -- > we need (589 - 453 =) 136 more bckg crops 158 | extraBckg = dataset == "Train" and 19 or 136 159 | nbBckg = dataset == "Train" and 1218 or 453 160 | bckgCrops = {} 161 | for i = 1, extraBckg do 162 | idx = math.random(nbBckg) 163 | bckgCrops[idx] = bckgCrops[idx] and bckgCrops[idx] + 1 or 2 164 | end 165 | 166 | cropWin = 128 -- images are 320 x 240 167 | srcBckgPath = '/Users/atcold/Work/Datasets/INRIAPerson/' .. dataset .. '/neg/*' 168 | for idx, fileName in ipairs(sys.split(sys.ls(srcBckgPath),'\n')) do 169 | for i = 1, bckgCrops[idx] or 1 do 170 | img = image.load(fileName) 171 | imgW = img:size(3) 172 | imgH = img:size(2) 173 | x = math.random(imgW - cropWin + 1) 174 | y = math.random(imgH - cropWin + 1) 175 | crop = img[{ {},{y,y+cropWin-1},{x,x+cropWin-1} }] 176 | 177 | saveName = string.match(fileName,'neg/(.+)%.') 178 | if bckgCrops[idx] then 179 | saveName = saveName .. '-' .. i 180 | end 181 | saveName = saveName .. '.png' 182 | 183 | --image.display{image = image.scale(crop,256,256), legend = 'Crop'} 184 | image.savePNG(bckgPath .. saveName, image.scale(crop,256,256)) 185 | end 186 | collectgarbage() 187 | end 188 | 189 | end 190 | --------------------------------------------------------------------------------