Programação 23/24 S2

Laboratório 1

Autor
Afiliação

CAP Diogo Silva

Academia da Força Aérea

Regras

  • Esta laboratório vale 1 valor (5%) da nota final da UC.
  • O laboratório tem a duração de 1 hora e é individual.
  • Para resolver os seguintes exercícios, podem ser usados:
    • computador
    • ambiente de desenvolvimento, sem assistências configuradas (e.g. Github Copilot)
    • folha de rascunho
    • caneta ou lápis
    • folha de consulta “cheatsheet”
  • Não podem ser consultados ou usados quaisquer outros recursos.
  • Em cima da mesa de trabalho não devem estar quaisquer outros objetos, à excepção de uma garrafa de água, se desejado.
  • O incumprimento das regras supracitadas levará à anulação do laboratório e consequente atribuição de pontuação 0.
  • Lê o enunciado com atenção e usa o código fornecido quando apropriado.

Exercício 1 - IoU [60%]

Contexto

Na área de visão computacional, em particular na deteção de objetos, a métrica Intersection over Union (IoU) mede a área da interseção entre uma deteção positiva de um objecto de interesse e as características verdadeiras desse mesmo objecto. A deteção é especificada por uma bounding box (BB).

A bounding box verde representa as características verdadeiras do objecto de interesse, enquanto a amarela representa as características da deteção de um modelo de aprendizagem automática. Fonte: Flickr FAP

As coordenadas de cada BB são identificadas com a nomenculatura aqui apresentada.

O cálculo de IoU é feita da seguinta foram:

Diagrama do cálculo da IoU. Fonte: Wikipedia

IoU = \frac{A_I}{A_U}

A_U = A_1 + A_2 - A_I

Onde:

  • A_I -> área da interção
  • A_U -> área da união
  • A_1 -> área da BB 1
  • A_2 -> área da BB 2

Objetivo

Escreve uma função chamada compute_iou que calcula a IoU a partir das coordenadas das 2 bounding boxes, onde:

  • BB 1 é definida por (x11, y11) para o canto superior esquerdo e (x12, y12) para o canto inferior direito
  • BB 2 é definida por (x21, y21) para o canto superior esquerdo e (x22, y22) para o canto inferior direito

Esta função deve portanto receber 8 números inteiros (correspondentes às 2 BB) e devolver um número real (IoU).

O funcionamento desta função pode ser validado com a lista no código fornecido. Em cada linha está um par de BB e o último valor é a IoU correspondente, i.e. \{x11, y11, x12, y12, x21, y21, x22, y22, iou\}.

Ajudas:

  1. para calcular a área de uma BB, é necessário calcular a altura e a largura, e multiplicar esses 2 valores;
  2. para calcular a área da interseção, é necessário calcular as dimensões do rectângulo interno, i.e.:
    1. a largura é a diferença entre o máximo dos cantos esquerdos (x11, x21) e o mínimo dos cantos direitos (x12, x22);
    2. altura é a diferença entre o máximo dos cantos superiores (y11, y21) e o mínimo dos cantos inferiores (y12, y22);
    3. atenção à direção dos eixos x e y;
  3. é necessário confirmar que existe interseção!

Exercício 2 - IoU Média [40%]

Na função main, implementa um programa completo que

  1. leia 50 pares de BB;
  2. calcule a IoU com a função implementada no exercício 1 para cada par;
  3. mostre na consola os parâmetros das BB e corerspondente IoU, e.g. BB 1: 478, 371, 754, 435 BB 2: 542, 381, 729, 424 IoU:0.4594 (não é necessário especial cuidado com a formatação de números reais);
  4. calcule a média de todas as IoU e apresente o valor na consola no final.

No código fornecido, existe uma função que quando invocada devolve um par de BB. Contudo, o valor fornecido utiliza registos. Para extrair os detalhes de cada BB, pode-se usar a seguinte lógica:

// como receber 1 par de bounding boxes
BBoxPair bb = fetch_next_bounding_box_pair();
// bb 1
int x11 = bb.x11, y11 = bb.y11, x12 = bb.x12, y12 = bb.y12;
// bb 2
int x21 = bb.x21, y21 = bb.y21, x22 = bb.x22, y22 = bb.y22;

Ajudas:

  1. É necessário implementar um ciclo e usar a lógica de leitura de BB durante 50 iterações.
  2. Se o exercício 2 não foi resolvido, pode-se usar os valores da IoU de cada par já previamente calculados para validação e usar esse valor para o cálculo da média, com um desconto de 25%, e.g.
// como receber 1 par de bounding boxes
BBoxPair bb = fetch_next_bounding_box_pair();
int x11 = bb.x11, y11 = bb.y11, x12 = bb.x12, y12 = bb.y12;
int x21 = bb.x21, y21 = bb.y21, x22 = bb.x22, y22 = bb.y22;
float iou = bb.iou; // IoU

Código fornecido - copiar

#include <stdio.h>

typedef struct {
    int x11, y11, x12, y12, x21, y21, x22, y22;
    float iou;
} BBoxPair;



BBoxPair bbs[] = {
//  { x11, y11, x12, y12, x21, y21, x22, y22, iou}
    { 478, 371, 754, 435, 542, 381, 729, 424, 0.45942793668425436 },
    { 303, 261, 615, 313, 325, 272, 513, 303, 0.36457893785038276 },
    { 604, 100, 658, 173, 604, 118, 638, 164, 0.40417690417690416 },
    { 119, 249, 497, 318, 185, 279, 400, 318, 0.3256690539012439 },
    { 191, 353, 394, 430, 229, 360, 385, 419, 0.5920060331825038 },
    { 289, 95, 648, 129, 335, 98, 538, 118, 0.34 },
    { 125, 452, 723, 489, 195, 465, 451, 485, 0.23710570248660048 },
    { 412, 19, 657, 499, 413, 50, 595, 406, 0.5521271740783936 },
    { 326, 75, 655, 99, 371, 78, 654, 98, 0.722909090909091 },
    { 768, 448, 788, 501, 768, 457, 788, 497, 0.7592592592592593 },
    { 160, 178, 241, 321, 165, 188, 215, 277, 0.38871951219512196 },
    { 125, 410, 150, 482, 130, 426, 150, 465, 0.44257112750263433 },
    { 221, 153, 422, 523, 324, 252, 405, 401, 0.16412692482186225 },
    { 397, 190, 705, 431, 443, 196, 695, 393, 0.6699029126213593 },
    { 730, 332, 755, 410, 730, 338, 751, 403, 0.7069133398247323 },
    { 747, 281, 797, 413, 752, 301, 790, 401, 0.5807164971251658 },
    { 5, 478, 751, 500, 30, 478, 715, 498, 0.8384843722716955 },
    { 553, 318, 656, 490, 580, 323, 637, 419, 0.3126945309026234 },
    { 733, 357, 791, 479, 754, 388, 785, 453, 0.2910293509714758 },
    { 451, 501, 474, 524, 454, 504, 474, 524, 0.765625 },
    { 524, 489, 748, 532, 562, 489, 736, 522, 0.601010101010101 },
    { 227, 160, 375, 511, 265, 260, 369, 507, 0.49649176327028677 },
    { 589, 406, 720, 504, 599, 440, 675, 497, 0.34175084175084175 },
    { 149, 289, 651, 517, 189, 392, 443, 507, 0.25679981247883876 },
    { 689, 346, 713, 366, 690, 346, 712, 366, 0.92 },
    { 82, 187, 126, 472, 85, 193, 123, 441, 0.7545454545454545 },
    { 477, 181, 699, 298, 566, 206, 695, 274, 0.34088318005624385 },
    { 492, 339, 543, 490, 495, 350, 542, 490, 0.8562753036437247 },
    { 694, 7, 799, 372, 697, 7, 795, 347, 0.8701670275286112 },
    { 481, 75, 704, 357, 494, 84, 674, 312, 0.6538522211004543 },
    { 91, 66, 406, 195, 133, 74, 377, 174, 0.6023612463485881 },
    { 504, 380, 594, 419, 515, 380, 587, 411, 0.6417582417582418 },
    { 724, 0, 764, 301, 730, 7, 752, 178, 0.3194960426425456 },
    { 149, 241, 563, 435, 281, 245, 558, 374, 0.4465863453815261 },
    { 763, 105, 795, 296, 767, 166, 787, 278, 0.37452651515151514 },
    { 559, 125, 711, 166, 567, 137, 670, 164, 0.4531590413943355 },
    { 288, 379, 726, 453, 299, 387, 687, 452, 0.7797722095671982 },
    { 358, 213, 647, 280, 368, 229, 580, 278, 0.5400608519269777 },
    { 647, 173, 728, 233, 665, 202, 690, 222, 0.10915633746501399 },
    { 360, 251, 576, 506, 366, 288, 546, 500, 0.6939984158986175 },
    { 72, 357, 673, 508, 260, 420, 564, 496, 0.25665544675642593 },
    { 645, 81, 691, 495, 652, 138, 690, 487, 0.699820558831069 },
    { 592, 458, 623, 508, 601, 462, 621, 490, 0.37316176470588236 },
    { 78, 140, 499, 197, 132, 150, 431, 190, 0.5025330936427521 },
    { 354, 443, 609, 528, 425, 451, 581, 503, 0.37795239825581395 },
    { 624, 359, 683, 428, 635, 383, 667, 420, 0.2985714285714286 },
    { 201, 272, 733, 329, 470, 286, 691, 309, 0.17234909749628 },
    { 571, 349, 800, 505, 603, 376, 782, 498, 0.6131265577402382 },
    { 608, 389, 709, 468, 608, 405, 673, 456, 0.42058823529411765 },
    { 605, 184, 659, 344, 606, 186, 647, 308, 0.583399209486166 },
};

int fetched_i=0;

// esta função simula a leitura de um par de bounding boxes
// sempre que for chamada, devolve um novo par de bounding boxes
// até que não haja mais pares para devolver
BBoxPair fetch_next_bounding_box_pair() {
    if (fetched_i >= sizeof(bbs)/sizeof(bbs[0])) {
        fetched_i = 0;
    }
    return bbs[fetched_i++];
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * *

         Função exercício 1  - calcular IoU

 * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * */

// escrever aqui a função do exercício 1


int main() {
    // NOTA
    // para o exercício 1, este código é inútil
    // escreve uma main diferente para verificar o funcionamento
    // da função do exercício 1

    int x11, y11, x12, y12, x21, y21, x22, y22;
    float iou;
    
    // como receber primeiro par de bounding boxes
    BBoxPair bb = fetch_next_bounding_box_pair();
    // bb 1
    x11 = bb.x11, y11 = bb.y11, x12 = bb.x12, y12 = bb.y12;
    // bb 2
    x21 = bb.x21, y21 = bb.y21, x22 = bb.x22, y22 = bb.y22;

    printf("par 1: x11=%d, y11=%d, ...\n", x11, y11);

    // como receber segundo par de bounding boxes
    bb = fetch_next_bounding_box_pair();
    x11 = bb.x11, y11 = bb.y11, x12 = bb.x12, y12 = bb.y12;
    x21 = bb.x21, y21 = bb.y21, x22 = bb.x22, y22 = bb.y22;
    printf("par 2: x11=%d, y11=%d, ...\n", x11, y11);

    return 0;
}