Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 172 lines (158 sloc) 5.726 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
/*
* Video Quality Assessment Tool using SSIM (VQATS).
* Written by Kah Keng Tay, kahkeng AT gmail DOT com, 2008.
*
* A* algorithm.
*/

#include "vqats.hh"
#include "dtable.hh"
#include "fib.h"

enum state_t
{
    NONE = 0,
    OPEN,
    CLOSED
};

struct QueueElement
{
    QueueElement(frame_t i1, frame_t i2): _i1(i1), _i2(i2), _estimate(0), _sum(0), _length(0) { }
    frame_t _i1, _i2;
    score_t _estimate; // estimated score
    score_t _sum; // cumulative score
    uint16_t _length; // path length
};

static inline int element_comparator(void* x, void* y)
{
    QueueElement* a = (QueueElement*)x;
    QueueElement* b = (QueueElement*)y;
    if (a->_estimate < b->_estimate) return -1;
    else if (a->_estimate > b->_estimate) return 1;
    else return 0;
}

static inline score_t element_heuristic(frame_t i1, frame_t i2, frame_t j1, frame_t j2)
{
    frame_t a1 = abs(i1 - j1);
    frame_t a2 = abs(i2 - j2);
    if (a1 > a2) return (a1 - a2) * (1.0 - DELETED_FRAME);
    else return (a2 - a1) * (1.0 - INSERTED_FRAME);
}

score_t compute_video_score(VQATS& v, const video_t& video1, const video_t& video2)
{
    frame_t n1 = v._video_map[video1]._frames.size();
    frame_t n2 = v._video_map[video2]._frames.size();
    void*** start_he = new_table<void*>(n1 + 1, n2 + 1, NULL); // heap elements
    QueueElement*** start_qe = new_table<QueueElement*>(n1 + 1, n2 + 1, NULL); // queue elements
    state_t** start_state = new_table<state_t>(n1 + 1, n2 + 1, NONE); // node states

    // initial values
    start_qe[0][0] = new QueueElement(0, 0);
    start_state[0][0] = OPEN;
    
    // initial queues
    struct fibheap* start_heap = fh_makeheap();
    fh_setcmp(start_heap, element_comparator);
    start_he[0][0] = fh_insert(start_heap, (void*)start_qe[0][0]);

    score_t sum = 0;
    uint16_t length = 0;
    int ninserts = 0;
#ifdef FH_STATS
    printf("maxinserts = %d\n", (n1+1)*(n2+1)); fflush(stdout);
#endif

    while (true)
    {
        QueueElement *qs, *qe;
        int i1, i2;
        score_t s;

        // check start frontier
        qs = (QueueElement*)fh_extractmin(start_heap);
        assert(qs); // there is always a path
        assert(start_state[qs->_i1][qs->_i2] == OPEN); // this node should be open
#ifdef DEBUG
        printf("extract from start: (%d,%d) est=%.4f sum=%.4f len=%d\n", qs->_i1, qs->_i2, qs->_estimate, qs->_sum, qs->_length);
#endif
        start_state[qs->_i1][qs->_i2] = CLOSED;
        if (qs->_i1 == n1 && qs->_i2 == n2) // we have found an optimal path
        {
            sum = qs->_sum;
            length = qs->_length;
            break;
        }
        // expand this node outward
        for (int dir = 0; dir < 3; dir++)
        {
            switch (dir)
            {
            case 0: i1 = qs->_i1 + 1; i2 = qs->_i2 + 1; break;
            case 1: i1 = qs->_i1; i2 = qs->_i2 + 1; break; // insert frame
            case 2: i1 = qs->_i1 + 1; i2 = qs->_i2; break; // delete frame
            }
            if (i1 <= n1 && i2 <= n2 && start_state[i1][i2] != CLOSED)
            {
                switch (dir)
                {
                case 0: s = 1.0 - v.compute_frame_score(video1, video2, i1 - 1, i2 - 1); break;
                case 1: s = 1.0 - INSERTED_FRAME; break;
                case 2: s = 1.0 - DELETED_FRAME; break;
                }
                qe = new QueueElement(i1, i2);
                qe->_sum = qs->_sum + s;
                qe->_length = qs->_length + 1;
                qe->_estimate = qe->_sum + element_heuristic(i1, i2, n1, n2);
                switch (start_state[i1][i2])
                {
                case NONE:
#ifdef DEBUG
                    printf("expanding start: (%d,%d) est=%.4f sum=%.4f len=%d\n", i1, i2, qe->_estimate, qe->_sum, qe->_length);
#endif
#ifdef FH_STATS
                    ninserts = fh_ninserts(start_heap);
                    if (ninserts % 10000 == 0) { printf("%d %d %d\n", ninserts, fh_nextracts(start_heap), fh_maxn(start_heap)); fflush(stdout); }
#endif
                    assert(start_qe[i1][i2] == NULL);
                    start_he[i1][i2] = fh_insert(start_heap, (void*)qe);
                    start_qe[i1][i2] = qe;
                    start_state[i1][i2] = OPEN;
                    break;
                case OPEN:
#ifdef DEBUG
                    printf("updating start: (%d,%d) est=%.4f sum=%.4f len=%d\n", i1, i2, qe->_estimate, qe->_sum, qe->_length);
#endif
                    assert(start_qe[i1][i2] != NULL);
                    if (qe->_estimate < start_qe[i1][i2]->_estimate)
                    {
                        start_qe[i1][i2] = qe;
                        qe = (QueueElement*)fh_replacedata(start_heap, (struct fibheap_el*)start_he[i1][i2], (void*)qe);
                    }
                    delete qe;
                    break;
                default:
                    assert(false); // should not reach here
                    break;
                }
            }
        }
    }
    assert(length > 0);

#ifdef DEBUG
    printf("Sum = %f\n", sum);
    printf("Length = %d\n", length);
#endif
#ifdef FH_STATS
    printf("MaxN = %d\n", fh_maxn(start_heap));
    printf("Inserts = %d\n", fh_ninserts(start_heap));
    printf("Extracts = %d\n", fh_nextracts(start_heap));
#endif
    fflush(stdout);

    // clean up
    fh_deleteheap(start_heap);
    for (uint16_t i1 = 0; i1 <= n1; i1++)
    {
        for (uint16_t i2 = 0; i2 <= n2; i2++)
        {
            if (start_qe[i1][i2])
                delete start_qe[i1][i2];
        }
    }
    delete_table(start_he, n1 + 1, n2 + 1);
    delete_table(start_qe, n1 + 1, n2 + 1);
    delete_table(start_state, n1 + 1, n2 + 1);

    return 1.0 - sum / length;
}
Something went wrong with that request. Please try again.