Skip to content

Commit 1568ce2

Browse files
authored
Add files via upload
1 parent e88a2c8 commit 1568ce2

20 files changed

+672
-0
lines changed

+helper/dist2bbox.m

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function boxesXYWH = dist2bbox(distance,anchorGrid)
2+
% Transform distance(ltrb) to box(xywh or xyxy)
3+
4+
xywh = true;
5+
dim=1;
6+
7+
% matrix divided into two along dim 1
8+
rb = distance(3:end,:);
9+
lt = distance(1:2,:);
10+
x1y1 = anchorGrid - lt;
11+
x2y2 = anchorGrid + rb;
12+
13+
if xywh
14+
cxy = (x1y1 + x2y2) ./ 2;
15+
wh = x2y2 - x1y1;
16+
end
17+
18+
boxesXYWH = vertcat(cxy, wh); % xywh bbox
19+
end

+helper/distributionFocalLoss.m

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
function boxes = distributionFocalLoss(boxes)
2+
% Distribution Focal Loss Module
3+
4+
sz = size(boxes);
5+
c1=16; % pre-specified
6+
7+
% compute batch. channel and anchors
8+
if size(sz,2)>2
9+
batch=sz(3);
10+
else
11+
batch = 1;
12+
end
13+
ch = sz(1);
14+
anchors = sz(2);
15+
16+
% Reshape Operation
17+
boxes = permute(boxes,[2,1,3,4]); % 1 d qual like python
18+
boxes = reshape(boxes,anchors,c1,4,batch);
19+
boxes = permute(boxes,[2,1,3,4]);
20+
21+
% Transpose Operation
22+
boxes = permute(boxes,[3,2,1,4]);
23+
24+
% softmax along the channel dimension
25+
boxes = softmax(dlarray(boxes,'SSC')); % produces a diff of 10^-3
26+
boxes = extractdata(boxes);
27+
28+
% 1-d conv operation
29+
% Define weights
30+
weights = [0:c1-1];
31+
m = size(boxes,1);
32+
n = size(boxes,2);
33+
weights = reshape(repmat(weights,m*n,1),m,n,[]);
34+
% Conv operation
35+
boxes = boxes .* weights;
36+
boxes = sum(boxes,3); % diff of 10^-2 because of above diff
37+
38+
% Reshape Operation
39+
boxes = permute(boxes,[2,1,3,4]);
40+
boxes = reshape(boxes,anchors,4,batch);
41+
boxes = permute(boxes,[2,1,3,4]);
42+
43+
end
44+
45+
46+
47+
48+
49+
50+
51+
52+
53+
54+
55+
56+

+helper/extractDetections.m

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
function [bboxes,scores,labelIds] = extractDetections(predictions,numClasses,confThreshold)
2+
3+
% Filter predictions by confidence threshold
4+
xc = max(predictions(5:end,:),[],1) > confThreshold; % candidates for each image
5+
6+
% TODO: Hardcoding now only one image
7+
% INDEXING REQUIRED if multiple images
8+
pred = predictions';
9+
pred = pred(xc(1,:),:);
10+
11+
% box, class
12+
box = pred(:,1:4);
13+
cls = pred(:,5:4+numClasses);
14+
15+
% convert [x_c y_c w h] to [xTopLeft yTopLeft w h]
16+
bboxesTopLeft = iConvertCenterToTopLeft(box);
17+
[classProbs, classIdx] = max(cls,[],2);
18+
scorePred = classProbs;
19+
classPred = classIdx;
20+
21+
% NMS
22+
[bboxes, scores, labelIds] = selectStrongestBboxMulticlass(bboxesTopLeft, scorePred, classPred ,...
23+
'RatioType', 'Union', 'OverlapThreshold', 0.45);
24+
end
25+
26+
27+
function bboxes = iConvertCenterToTopLeft(bboxes)
28+
bboxes(:,1) = bboxes(:,1)- bboxes(:,3)/2 + 0.5;
29+
bboxes(:,2) = bboxes(:,2)- bboxes(:,4)/2 + 0.5;
30+
bboxes = floor(bboxes);
31+
bboxes(bboxes<1)=1;
32+
end

+helper/getCOCOClassNames.m

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
function classNames = getCOCOClassNames()
2+
% getCOCOClassNames function returns the names of COCO dataset classes.
3+
4+
% Copyright 2023 The MathWorks, Inc.
5+
6+
classNames={'person'
7+
'bicycle'
8+
'car'
9+
'motorbike'
10+
'aeroplane'
11+
'bus'
12+
'train'
13+
'truck'
14+
'boat'
15+
'traffic light'
16+
'fire hydrant'
17+
'stop sign'
18+
'parking meter'
19+
'bench'
20+
'bird'
21+
'cat'
22+
'dog'
23+
'horse'
24+
'sheep'
25+
'cow'
26+
'elephant'
27+
'bear'
28+
'zebra'
29+
'giraffe'
30+
'backpack'
31+
'umbrella'
32+
'handbag'
33+
'tie'
34+
'suitcase'
35+
'frisbee'
36+
'skis'
37+
'snowboard'
38+
'sports ball'
39+
'kite'
40+
'baseball bat'
41+
'baseball glove'
42+
'skateboard'
43+
'surfboard'
44+
'tennis racket'
45+
'bottle'
46+
'wine glass'
47+
'cup'
48+
'fork'
49+
'knife'
50+
'spoon'
51+
'bowl'
52+
'banana'
53+
'apple'
54+
'sandwich'
55+
'orange'
56+
'broccoli'
57+
'carrot'
58+
'hot dog'
59+
'pizza'
60+
'donut'
61+
'cake'
62+
'chair'
63+
'sofa'
64+
'pottedplant'
65+
'bed'
66+
'diningtable'
67+
'toilet'
68+
'tvmonitor'
69+
'laptop'
70+
'mouse'
71+
'remote'
72+
'keyboard'
73+
'cell phone'
74+
'microwave'
75+
'oven'
76+
'toaster'
77+
'sink'
78+
'refrigerator'
79+
'book'
80+
'clock'
81+
'vase'
82+
'scissors'
83+
'teddy bear'
84+
'hair drier'
85+
'toothbrush'};
86+
end

+helper/make_anchors.m

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function [anchorGrid, stride] = make_anchors(feats, strideValues)
2+
% feats - cell array containing output features
3+
% gridCellOffset = 0.5 - value to shift the z,y values by
4+
5+
gridCellOffset = 0.5;
6+
n = 3;
7+
anchorGridTmp = cell(n,1);
8+
strideTmp = cell(n,1);
9+
totalSize = 0;
10+
11+
for i = 1:n
12+
sz = size(feats{i});
13+
totalSize = totalSize + (sz(1).*sz(2));
14+
anchorGridTmp{i,1} = coder.nullcopy(zeros(sz(1).*sz(2),2));
15+
strideTmp{i,1} = coder.nullcopy(zeros(sz(1).*sz(2),2));
16+
end
17+
18+
for i=1:size(strideValues,2)
19+
[h,w,~,~]= size(feats{i});
20+
sx = (0:w-1)+gridCellOffset;
21+
sy = (0:h-1)+gridCellOffset;
22+
[sy,sx]= meshgrid(sy,sx);
23+
anchorGridTmp{i,1} = cat(2, sx(:), sy(:));
24+
strideTmp{i,1} = repmat(strideValues(i),h*w,1);
25+
end
26+
anchorGrid = cat(1,anchorGridTmp{:});
27+
stride = cat(1,strideTmp{:});
28+
end

+helper/per.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function op = per(op)
2+
if size(size(op),2)==4
3+
op = permute(op,[3,4,2,1]);
4+
5+
else
6+
op = permute(op,[2,3,1]);
7+
end
8+
end

+helper/postProcessYOLOv8.m

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
function newCoords = postProcessYOLOv8(img1_shape,coords,img0_shape)
3+
4+
% Rescale coords (xyxy) from img1_shape to img0_shape
5+
gain = min(img1_shape(1) / img0_shape(1), img1_shape(2) / img0_shape(2));
6+
pad = coder.nullcopy(zeros(1,2));
7+
pad(1) = (img1_shape(2) - img0_shape(2) * gain)./ 2;
8+
pad(2) = (img1_shape(1) - img0_shape(1) * gain)./ 2;
9+
10+
newCoords = coords - repmat(pad,size(coords,1),2);
11+
newCoords = newCoords./gain;
12+
newCoords(newCoords<0) = 0.1;
13+
14+
newCoords(:,1) = min(newCoords(:,1),img0_shape(2));
15+
newCoords(:,2) = min(newCoords(:,2),img0_shape(1));
16+
newCoords(:,3) = min(newCoords(:,3),img0_shape(2));
17+
newCoords(:,4) = min(newCoords(:,4),img0_shape(1));
18+
19+
end

+helper/postprocess.m

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function [bboxes,scores,labelIds] = postprocess(outFeatureMaps, origSize, newSize, numClasses)
2+
% The postprocess function applies postprocessing on the generated feature
3+
% maps and returns bounding boxes, detection scores and labels.
4+
5+
% Copyright 2024 The MathWorks, Inc.
6+
7+
% Transform outFeatureMaps to box [x_center y_center w h] and class scores
8+
[box cls] = helper.yolov8Transform(outFeatureMaps, numClasses);
9+
10+
% Map network predictions to anchor girds.
11+
predictions = cat(1, box, cls);
12+
confThreshold = 0.5;
13+
14+
% Extract detections from predictions.
15+
[bboxesPred,scores,labelIds] = helper.extractDetections(predictions, numClasses, confThreshold);
16+
bboxesTmp = xywhToX1Y1X2Y2(bboxesPred);
17+
18+
% Map predictions back to original dimension.
19+
bboxesPost = helper.postProcessYOLOv8(newSize, bboxesTmp, origSize);
20+
bboxes = x1y1x2y2ToXYWH(bboxesPost);
21+
22+
end
23+
24+
function boxes = xywhToX1Y1X2Y2(boxes)
25+
% Convert [x y w h] box to [x1 y1 x2 y2]. Input and output
26+
% boxes are in pixel coordinates. boxes is an M-by-4
27+
% matrix.
28+
boxes(:,3) = boxes(:,1) + boxes(:,3) - 1;
29+
boxes(:,4) = boxes(:,2) + boxes(:,4) - 1;
30+
end
31+
32+
function boxes = x1y1x2y2ToXYWH(boxes)
33+
% Convert [x1 y1 x2 y2] boxes into [x y w h] format. Input and
34+
% output boxes are in pixel coordinates. boxes is an M-by-4
35+
% matrix.
36+
boxes(:,3) = boxes(:,3) - boxes(:,1) + 1;
37+
boxes(:,4) = boxes(:,4) - boxes(:,2) + 1;
38+
end

+helper/preprocess.m

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function output = preprocess(img,targetSize)
2+
% This function preprocesses the input image.
3+
4+
% Copyright 2024 The MathWorks, Inc.
5+
6+
imgSize = size(img,1:2);
7+
8+
% Compute scaling ratio
9+
scaleRatio = min(targetSize(1)./ imgSize(1), targetSize(2) / imgSize(2));
10+
padSize = [round(imgSize(1) * scaleRatio), round(imgSize(2) * scaleRatio)];
11+
12+
% Compute padding values
13+
dw = targetSize(1) - padSize(2); % w padding
14+
dw = mod(dw, 32); % w padding
15+
dw = dw./2; % divide padding into 2 sides
16+
17+
dh = targetSize(2) - padSize(1); % h padding
18+
dh = mod(dh, 32); % h padding
19+
dh = dh./2; % divide padding into 2 sides
20+
21+
% Resize input image
22+
I = imresize(img, padSize,'bilinear',Antialiasing = false);
23+
24+
% Pad values to the image
25+
top = round(dh - 0.1);
26+
bottom = round(dh + 0.1);
27+
left = round(dw - 0.1);
28+
right = round(dw + 0.1);
29+
30+
I = padarray(I,[top left],114,'pre');
31+
I = padarray(I,[bottom,right],114,'post');
32+
33+
% Convert uint8 to single
34+
I = single(I);
35+
36+
% Rescale image pixes to [0,1]
37+
output = I./255;
38+
end

+helper/yolov8Transform.m

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
function [box, cls] = yolov8Transform(predictions,numClasses)
2+
% Transforms predictions from dlnetwork to
3+
% box [x_center y_center w h] and cls scores
4+
5+
regMax = 16;
6+
outputsPerAnchor = numClasses + regMax*4;
7+
stride = [8,16,32];
8+
batch = 1;
9+
10+
% Extract feature maps from Matlab model
11+
% Apply this if dlarray output
12+
predictions = cellfun(@extractdata,predictions,'UniformOutput',false);
13+
predictions = cellfun(@gather,predictions,'UniformOutput',false);
14+
15+
% Compute anchor grid and stride
16+
[anchorGrid, stride] = helper.make_anchors(predictions, stride);
17+
% anchor grid and stride transposed
18+
anchorGrid = anchorGrid';
19+
stride = stride';
20+
21+
% Reshape predictions from model output
22+
pred = cellfun(@(p){permute(p,[2,1,3,4])}, predictions, 'UniformOutput',true);
23+
pred = cellfun(@(p){reshape(p,[],outputsPerAnchor, batch)}, pred, 'UniformOutput',true);
24+
pred = cellfun(@(p){permute(p,[2,1,3,4])}, pred, 'UniformOutput',true);
25+
26+
% Concat all Predictions
27+
predCat = cat(2,pred{:});
28+
29+
% Split classes and boxes
30+
box = predCat(1:64,:,:);
31+
cls = predCat(65:end,:,:);
32+
33+
box = helper.distributionFocalLoss(box);
34+
% Converting boxes to xywh format here
35+
box = helper.dist2bbox(box,anchorGrid);
36+
box = box .* stride;
37+
% Sigmoid of classes
38+
cls = sigmoid(dlarray(cls));
39+
cls = extractdata(cls);
40+
end

0 commit comments

Comments
 (0)