2

This is going to be lengthy, so I apologize ahead of time. But I want to make sure the context is understood, as I have read numerous posts already on the subject. None that I have found solve the problem of tally the numbers based on an unknown range of numbers.

I am trying to determine the total occurrences of each integer for a set. The issue I am having is that, the test set would be fixed, say an array of 10 numbers, but the range of each number is unknown. The problem posed is that when trying to use an array to tally the totals, the array range cannot be variable at run-time. I retried this attempt using vector<int> ArrayName, whereas I could re-size the array of totals at run-time, but ran into errors using the vector<int> values in calculations.

The code I will be presenting is use of OpenCV for face detection. I've studied and utilized code from various samples to create a basic detection program, then studied and ported some Java code to handle tracking when a face has moved and update to it's new location. All of this code is working.

Where I would like to use the requested information, is that I want to store an array of the last, say 10, subjects detected of a face and find the one most detected over time and consider it as the subject. Let's say, we are detecting 10, and the last ten frames were detected as follows (-1 is unknown face): -1, -1, 0, 0, 0, 3, 0, -1, 0, 2. After the tallies, 0 occurred most frequently and therefor the subject is 0. The reason the Range is unknown, is because the subject ID is dependent on the number of subjects trained and is always changing.

The three errors are ( and denoted by //ERROR ):

invalid use of member (did you forget the '&' ?), 
no match for call to '(std::vector<int>) (int)', 
no match for call to '(std::vector<int>) (int)&'

Here is the code:

    struct FaceStruct {
    private:
        static const int NewLife = 120; //Divide by FPS for Length in Time
        static const int TotalTrackedSubjects = 10;
        int Life;
        vector<int> Subjects;
    public:
        void Init( Rect, int );
        void addSubject( int );
        int Subject();
        Rect Location;
        bool Used;
        void Weaken();
        void Renew();
        bool Dead();
    };
    void FaceStruct::Init( Rect location, int subject = -1 ) {
        Location = location;
        Subjects.resize( TotalTrackedSubjects - 1 );
        for( int i = 0; TotalTrackedSubjects - 1; i++ ) {
            Subjects(i) = -1; //ERROR
        }
        Renew();
    }
    void FaceStruct::addSubject( int subject ) {
        for( int i = 0; TotalTrackedSubjects - 2; i++ ) {
            Subjects(i) = Subjects( i + 1 );  //ERROR
        }
        Subjects( TotalTrackedSubjects - 1 ) = subject;  //ERROR
    }
    int FaceStruct::Subject() {
        int count_range = -1;
        for( int i = 0; TotalTrackedSubjects - 1; i++ ) {
            if( Subjects(i) > count_range ) count_range = Subjects(i); //ERROR
        }
        if( count_range < 0 ) { //Subject Unknown
            return -1;
        } else if( count_range == 0 ) { //Subject is 0, Handle 0's
            int totals = 0;
            for( int i = 0; TotalTrackedSubjects - 1; i++ ) {
                if( Subjects(i) == 0 ) totals++; //ERROR
            }
            return totals;
        } else { //Use count_range
            vector<int> totals;
            int unknowns = 0;
            totals.resize( count_range );
            for( int i = 0; TotalTrackedSubjects - 1; i++ ) {
                if( Subjects(i) < 0 ) { //ERROR
                    unknowns++;
                } else {
                    totals( Subjects(i) ) = totals( Subjects(i) ) + 1; //ERROR
                }
            }
            int largest = -1;
            for( int i = 0; totals.size() - 1; i++ ) {
                if( totals(i) > largest ) largest = totals(i); //ERROR
            }
            return largest;
        }
    }
    void FaceStruct::Weaken() {
        Life--;
    }
    void FaceStruct::Renew() {
        Life = NewLife;
    }
    bool FaceStruct::Dead() {
        if( Life < 1 ) {
            return true;
        } else {
            return false;
        }
    }
iDev
  • 23,310
  • 7
  • 60
  • 85
Nick B.
  • 23
  • 3
  • 2
    I think you to read [some books on C++](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) before going any further. When does your for loops stop? – Jesse Good Oct 10 '12 at 20:48
  • I've never had a problem here before. TotalTrackedSubjects is defined at the top of the Struct as a const int 10, there for it would end at 10 - 1... no? – Nick B. Oct 10 '12 at 21:11
  • That doesn't count from 0 to 9 if that's what you think it does. – hookenz Oct 10 '12 at 21:14
  • You are correct, sorry. I left out the i <. As I said below in another comment, I wrote this super fast so I could post the question and had some pretty standard errors. – Nick B. Oct 10 '12 at 21:27

4 Answers4

1

to access an item in an array you should use [] instead of ()

so Subjects(i) should be Subjects[i] and
totals( Subjects(i) ) = totals( Subjects(i) ) + 1; should be totals[ Subjects[i] ] = totals[ Subjects[i] ] + 1;

Adrian Herea
  • 658
  • 6
  • 7
  • You are totally right. I wrote code yesterday that failed and scrapped it. I then rewrote it today in about five minutes so I could ask the question... Let me fix and see what happens this time. – Nick B. Oct 10 '12 at 20:55
  • Fixing the ()s certainly took out all the errors and the project compiled just fine, but now I have an unknown crash when executing. I will research further. – Nick B. Oct 10 '12 at 21:10
  • I do believe the use of MAP is a better solution here, and less intensive. However, for the scope of the code and question posed, and I submitting this as the solution. I do not know why the code I wrote yesterday did not work, but correcting the [] and inserting the i < into the existing code (plus a few match errors I had) solved the problem and the code is now functioning as expected. – Nick B. Oct 10 '12 at 21:40
1

Sounds like something a map could do fairly well...

#include <map>

int example_values[10] = {-1, -1, 0, 0, 0, 3, 0, -1, 0, 2};

map<int, int> counts;
for (int i = 0; i < 10; ++i) ++counts[example_values[i]];

for (map<int, int>::iterator i = counts.begin(); i != counts.end(); ++i)
    cout << i->first << ": " << i->second << endl;

Output:

-1: 3
0: 5
2: 1
3: 1

(They might not be in that order. I feel like they will be but I forget exactly how maps order their contents.)

Wug
  • 12,956
  • 4
  • 34
  • 54
0

There are a few issues with the code:

1) Array access for vectors uses the array subscript operator [] not the function operator ()

2) Naming of methods and members uses inconsistent styling, members and methods should be distinguishable based on name only. Having a member and method differ by only a single easily missed 's' is asking for trouble.

3) Consider using a map or priority queue instead of a vector, which should remove a lot of non algorithmic detail.

Ian
  • 183
  • 1
  • 7
0

Your loop conditions look wrong.

for( int i = 0; TotalTrackedSubjects - 1; i++ ) {

Which is equivalent to writing:

int i = 0;
while(9){
  ...
  i++
}

The second part of the for loop construct is the exit condition.

I think that be:

for( int i = 0; i < TotalTrackedSubjects; i++ ) {

Otherwise your loop will never stop.

hookenz
  • 36,432
  • 45
  • 177
  • 286