I have a matrix that is dynamically being changed according to the following code;
for( It=all_frames.begin(); It != all_frames.end(); ++It)
{
ItTemp = *It;
subtract(ItTemp, Base, NewData);
cout << "The size of the new data for ";
cout << " is \n" << NewData.rows << "x" << NewData.cols << endl;
cout << "The New Data is: \n" << NewData << endl << endl;
NewData_Vector.push_back(NewData.clone());
}
What I want to do is determine the frames at which the cv::Mat NewData is a zero matrix.
I've tried comparing it to a zero matrix that is of the same size, using both the cv::compare() function and simple operators (i.e NewData == NoData), but I can't even compile the program.
Is there a simple way of determining when a cv::Mat is populated by zeroes?
I used
if (countNonZero(NewData) < 1)
{
cout << "Eye contact occurs in this frame" << endl;
}
This is a pretty simple (if perhaps not the most elegant) way of doing it.
To check the mat if is empty, use empty(), if NewData is a cv::Mat, NewData.empty() returns true if there's no element in NewData.
To check if it's all zero, simply, NewData == Mat::zeros(NewData.size(), NewData.type()).
Update:
After checking the OpenCV source code, you can actually do NewData == 0 to check all element is equal to 0.
countNonZero(Mat ) will give u number of non zeros in mat
How about this..
Mat img = Mat::zeros(cvSize(1024, 1024), CV_8UC3);
bool flag = true;
MatConstIterator_<double> it = img.begin<double>();
MatConstIterator_<double> it_end = img.end<double>();
for(; it != it_end; ++it)
{
if(*it != 0)
{
flag = false;
break;
}
}
The Mat object has an empty property, so you can just ask Mat to tell you if it has something or it's empty. The result will be either true or false.
Related
I am making a D&D game in C++. I roll 6 scores randomly, put them in a vector, display them to the player. Then I go through each ability (str, dex, con, int, wis, and cha), and call a function that asks the player which of the scores they want to use for each ability, and then i remove it from the vector, return the value, and move on to the next ability. It works fine unless there is a duplicate roll, in which case it deletes both of the duplicates. I want it to only remove one at a time regardless of duplicates, and I haven't been able to find anything online to do this. Here is the function call
int Character::initScores(std::vector<int> & v, std::string ability)
{
int c = 0;
bool error = 0;
do {
if (c != 0) {
std::cout << "That isn't one of your scores. Try again. " <<
std::endl;
}
int choice;
std::cout << ability << ": ";
std::cin >> choice;
if (std::find(v.begin(), v.end(), choice) != v.end())
{
v.erase(std::remove(v.begin(), v.end(), choice), v.end());
std::cout << "Your remaining rolls are ";
for (int i = 0; i < v.size(); i++)
std::cout << v[i] << " ";
std::cout << std::endl;
return choice;
}
else
{
c++;
error = 1;
}
} while (error = 1);
}
And the function calls
std::cout << "Enter which score you want for... " << std::endl;
strength = initScores(scores, "Strength");
dexterity = initScores(scores, "Dexterity");
constitution = initScores(scores, "Constitution");
intelligence = initScores(scores, "Intelligence");
wisdom = initScores(scores, "Wisdom");
charisma = initScores(scores, "Charisma");
Also please lmk if there is anything inefficient/bad practice in my code, I have only recently started working on my own coding projects
You are calling std::remove(), which "removes" ALL matching values from the container (really, it just moves them to the end of the container), and then you are calling the 2-parameter overload of the erase() method to physically delete ALL of the "removed" values from the container.
If you just want to remove 1 element, pass the iterator returned by std::find() to the 1-parameter overload of the erase() method:
auto iter = std::find(v.begin(), v.end(), choice);
if (iter != v.end())
{
v.erase(iter);
...
}
I am supposed to read some data (specifically string datatype) and store each element in a vector. Now I have to check if any of the different strings that were inputted match in size, and if they do I have to see if there are any matching letters. Now my question is how do I compare what's inside the vector (first the size and then the different letters). Is it possible?
Say I have
HELLO
and
HELLA
They have the same size, and 4 letters that match.
This is what I am trying to accomplish.
The code that I have does not work given my ignorance about the matter.
Thank you in advance.
vector <string> myVector;
//insert data insdide of the vector
myVector.push_back("Hello");
myVector.push_back("Hello");
myVector.push_back("Hello2");
myVector.push_back("Hello3");
myVector.push_back("Hello4");
//This is wrong
for (unsigned int i = 0; i < myVector.size(); i++) {
if (myVector[i].size == myVector[i+1].size()){
cout << "SAME SIZE" << endl;
}
}
return 0;
You just have make a simple mistake for size() function and you are trying to access the element which is not present by using i+1 for last iteration.
So just change your for loop just as below
for (unsigned int i = 1; i < myVector.size(); i++)
{
if (myVector[i].size() == myVector[i-1].size()) // .size() should be used
{
cout << "SAME SIZE" << endl;
}
}
Here's a way of writing it:
// returns true if #param s1 and #param s2 are equal in letters
bool isEqual(const string& s1, const string& s2) {
if(s1.size() != s2.size())
return false;
bool equal = false;
// iterates over all the characters in s1 and s2 and compare them
for(auto ch1 = s1.cbegin(), ch2 = s2.cbegin(); ch1 != s1.cend(),ch2!= s2.cend(); ch1++, ch2++) {
if(*ch1 == *ch2)
equal = true;
else
return false;
}
return equal;
}
// type of iter is vector<string>::const_iterator meaning it can only read the value
for (auto iter = myVector.cbegin(); iter != myVector.cend() - 1; iter++){
if(isEqual(*iter, *(iter + 1)))
std::cout << *iter << " equal " << *(iter + 1) << endl;
else
std::cout << *iter << " different " << *(iter + 1) << endl;
}
Here, I used iterators(you should write code in modern C++, avoid using subscript).
I have a std::set of strings and I want to iterate over them, but the iterator is behaving differently for different sizes of set. Given below is the code snippet that I'm working on:
int test(set<string> &KeywordsDictionary){
int keyword_len = 0;
string word;
set<string>::iterator iter;
cout << "total words in the database : " << KeywordsDictionary.size() << endl;
for(iter=KeywordsDictionary.begin();iter != KeywordsDictionary.end();iter++) {
cout << *iter;
word = *iter;
keyword_len = word.size();
if(keyword_len>0)
Dosomething();
else
cout << "Length of keyword is <= 0" << endl;
}
cout << "exiting test program" << endl;
}
The code is working properly & *iter is being dereferenced & assigned to word until the size of KeywordsDictionary is around 15000. However when the size of KeywordsDictionary increases beyond 15000,
the print statement cout << *iter; is printing all the contents of KeywordsDictionary correctly.
but the pointer to the iterator *iter is not being dereferenced & not being assigned to word. word is just being an empty string.
EDIT: And the output of the program is :
total words in the database : 22771
�z���AAAADAAIIABABBABLEABNABOUTACACCEPTEDACCESSACCOUNT...
Length of keyword is <= 0
exiting test program
So basically, I'm guessing the loop is executing only once.
Try to declare keyword_len as
std::string::size_type keyword_len = 0;
instead of
int keyword_len = 0;
Im having trouble accessing the following vector. Im new to vectors so this is probably a small syntactical thing i've done wrong. here is the code....
void spellCheck(vector<string> * fileRead)
{
string fileName = "/usr/dict/words";
vector<string> dict; // Stores file
// Open the words text file
cout << "Opening: "<< fileName << " for read" << endl;
ifstream fin;
fin.open(fileName.c_str());
if(!fin.good())
{
cerr << "Error: File could not be opened" << endl;
exit(1);
}
// Reads all words into a vector
while(!fin.eof())
{
string temp;
fin >> temp;
dict.push_back(temp);
}
cout << "Making comparisons…" << endl;
// Go through each word in vector
for(int i=0; i < fileRead->size(); i++)
{
bool found = false;
// Go through and match it with a dictionary word
for(int j= 0; j < dict.size(); j++)
{
if(WordCmp(fileRead[i]->c_str(), dict[j].c_str()) != 0)
{
found = true;
}
}
if(found == false)
{
cout << fileRead[i] << "Not found" << endl;
}
}
}
int WordCmp(char* Word1, char* Word2)
{
if(!strcmp(Word1,Word2))
return 0;
if(Word1[0] != Word2[0])
return 100;
float AveWordLen = ((strlen(Word1) + strlen(Word2)) / 2.0);
return int(NumUniqueChars(Word1,Word2)/ AveWordLen * 100);
}
The error is in the lines
if(WordCmp(fileRead[i]->c_str(), dict[j].c_str()) != 0)
and
cout << fileRead[i] << "Not found" << endl;
the problem seems to be, because its in the form of a pointer the current syntax im using to access it is made invalid.
Using [] on a pointer to a vector will not call std::vector::operator[]. To call std::vector::operator[] as you want, you must have a vector, not a vector pointer.
The syntax to access the n-th element of a vector with a pointer to the vector would be: (*fileRead)[n].c_str().
However, you should just pass a reference to the vector:
void spellCheck(vector<string>& fileRead)
Then it's just:
fileRead[n].c_str()
You can use the unary * to get a vector& from a vector*:
cout << (*fileRead)[i] << "Not found" << endl;
Two options to access:
(*fileRead)[i]
fileRead->operator[](i)
One option to improve the method
pass by reference
You can either pass fileRead by reference like this:
void spellCheck(vector<string> & fileRead)
Or add a dereferece when you use it like this:
if(WordCmp( (*fileRead)[i]->c_str(), dict[j].c_str()) != 0)
My remove_if seems to be overwriting the elements that are not filtered out with values of filtered out elements. The purpose of these code is to allow user to filter and display only teacher from a certain category. (Not deleting any element)
Here are some of the code
static string compare;
static string debug;
bool filter_Cat (Teacher &t)
{
return (t.getCat() != compare);
}
void filterCat (vector<Teacher> &t)
{
vector<Teacher>::iterator i;
vector<Teacher>::iterator newedited = remove_if(t.begin(), t.end(), filter_Cat);
for (i = t.begin(); i != newedited; ++i)
{
Teacher& te = *i;
te.getName();
cout << "\t";
te.getCategory();
cout << "\t";
te.getLocation();
}
}
void filterTutorCat(vector<Teacher> &t)
{
int choice;
cout << "No\tCategory" << endl
<< "1\tEnglish" << endl
<< "2\tMath" << endl
<< "3\tScience" << endl
<< "Choose the category you wish to filter :";
cin >> choice;
getline(cin, debug);
if(choice <= 3 && choice > 0)
{
if (choice == 1)
{
compare = "English";
filterCat(t);
}
if (choice == 2)
{
compare = "Math";
filterCat(t);
}
if (choice == 3)
{
compare = "Science";
filterCat(t);
}
}
else
{
cout << "Invalid Option" << endl;
}
}
remove_if shifts elements, for which the compare function returns false, from right to left; which in other words means, it overwrites the elements, for which compare returns true, with elements, for which compare returns false. The size of the vector doesn't change, however.
This reads,
Removes all elements satisfying specific criteria from the range [first, last). The first version removes all elements that are equal to value, the second version removes all elements for which predicate p returns true.
Removing is done by shifting the elements in the range in such a way that elements to be erased are overwritten. The elements between the old and the new ends of the range have unspecified values. Iterator to the new end of the range is returned. Relative order of the elements that remain is preserved.
So what you want to do should be expressed as:
void filterCat (vector<Teacher> &v)
{
for (vector<Teacher>::iterator it = v.begin(); it != v.end() ; ++it)
{
if (!filter_Cat(*i))
{
std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
}
}
}
It seems in your code, getName() prints the name which ideally it should not do, instead it should return name. So I would suggest you to change it to make it return name. And do the same for getCategory as well. Choose your name correctly. If it is getName(), you should get you name by returning it; if it is printName(), then it should print name.
Also, the code which you've written isn't good:
You should avoid global variables.
You should avoid if-else as much as possible. Learn better ways.
You should learn about function objects (or functor)
You should learn about const member function.
You should understand the difference between iterator and const_iterator, and their usage.
You should understand the difference between const reference, and non-const reference. And try using them appropriately.
So I would write your code as:
//this is functor, not a function
struct filter_cat
{
std::string m_cat; //use member data, avoid global variable
filter_cat(std::string const & cat) : m_cat(cat) {}
bool operator()(Teacher const & t) const //const member function
{
return (t.getCat() != m_cat); //getCat should be const member function
}
};
//pass vector by const reference
void filterCat (vector<Teacher> const & v, filter_cat filter)
{
//use const_iterator here, instead of iterator
for (vector<Teacher>::const_iterator it = v.begin(); it != v.end() ; ++it)
{
if (!filter(*i))
{
//getName and getCategory should be const member function
std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
}
}
}
void filterTutorCat(vector<Teacher> const &t)
{
int choice;
cout << "No\tCategory" << endl
<< "1\tEnglish" << endl
<< "2\tMath" << endl
<< "3\tScience" << endl
<< "Choose the category you wish to filter :";
cin >> choice;
getline(cin, debug);
//avoid if-else as much as possible, learn better ways!
std::string cats[] = {"English", "Math", "Science"};
if(choice <= 3 && choice > 0)
{
filterCat(v, filter_cat(cats[choice-1]));
}
else
{
cout << "Invalid Option" << endl;
}
}
As noted in the comments: getCat, getName and getCategory should be const member functions. In fact, if getCategory returns category, then getCat isn't even needed.
Solved my issue.
remove_if collects the values for which filter_Cat returns false at the start of the container. While it doesn't reduce the number of elements in the container it neither does make any guarantees about the values of the elements beyond the returned range. So you are loosing values when using remove_if.