pHash returning different hash lenght - c++

I have the following code:
fingerprint.cpp:
#include <iostream>
#include <filesystem>
#include "ImageHash.h"
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include <opencv2/imgcodecs.hpp>
using namespace std;
void usage (char** argv) noexcept {
cout << "Usage: " << argv[0] << " <image or dir>" << endl << "Example: " << argv[0] << " template.png" << endl;
}
int main(int argc, char** argv) {
if (argc != 2) {
usage(argv);
return 1;
}
auto imgHash = ImageHash();
if (std::filesystem::is_directory(argv[1])) {
for (const auto& dirEntry : std::filesystem::recursive_directory_iterator(argv[1])) {
auto filePath = dirEntry.path();
std::string fileName = dirEntry.path().filename().string();
cv::Mat img = cv::imread(filePath.string(), cv::IMREAD_GRAYSCALE);
img.resize(8*8);
/*cv::imshow("img", img);
cv::waitKey();*/
cout << fileName << "\t\t" << imgHash.getHashString(img) << endl;
}
}
else if (std::filesystem::is_regular_file(argv[1])){
cv::Mat img = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
cout << std::filesystem::path(argv[1]).filename().string() << "\t\t" << imgHash.getHashString(img) << endl;
}
else {
usage(argv);
}
return 0;
}
ImageHash.cpp:
#include "ImageHash.h"
#include <iomanip>
using namespace std;
ImageHash::ImageHash()
{
pHash = cv::img_hash::PHash::create();
}
std::string ImageHash::convertHashToString(vector<bool> hash) {
std::string ret = "";
double h = 0;
for (unsigned int i = 0; i < hash.size(); i++) {
if (hash[i]) {
h += pow(2, (i % 8));
}
if (i % 8 == 7) {
std::stringstream buffer;
buffer << std::hex << std::setfill('0') << std::setw(2) << h;
ret += buffer.str();
h = 0;
}
}
return ret;
}
std::vector<bool> ImageHash::hex_str_to_hash(std::string inputString) {
std::vector<bool> hash;
size_t size = inputString.size() / 2;
for (int i = 0; i < size; i++) {
std::string str2 = inputString.substr(i * 2, 2);
if (str2.empty()) {
continue;
}
unsigned int value = 0;
std::stringstream SS(str2);
SS >> std::hex >> value;
for (int j = 0; j < 8; j++) {
bool check = !!((value >> j) & 1);
hash.push_back(check);
}
}
return hash;
}
std::vector<bool> ImageHash::matHashToBoolArr(cv::Mat const inHash) {
const unsigned char* data = inHash.data;
std::vector<bool> v;
for (int i = 0; i < 8; i++) {
unsigned char c = data[i];
for (int j = 0; j < 8; j++) {
int shift = (8 - j) - 1;
bool val = ((c >> shift) & 1);
v.push_back(val);
}
}
return v;
}
std::vector<bool> ImageHash::computeHash(cv::Mat const input) {
cv::Mat inHash;
pHash->compute(input, inHash);
return matHashToBoolArr(inHash);
}
std::string ImageHash::getHashString(cv::Mat const input) {
return convertHashToString(computeHash(input));
}
//returns hamming distance
int ImageHash::getHashDistance(std::vector<bool>& hash1, std::vector<bool>& hash2) {
//assert(hash1.size() == hash2.size());
/* ToDo: I don't know why the size is not the same but if if is lets add padding to the smaller one
This does not seem to make it work*/
if (hash1.size() != hash2.size()) {
auto smaller = hash1.size() < hash2.size() ? &hash1 : &hash2;
auto larger = hash1.size() < hash2.size() ? hash2 : hash1;
smaller->resize(larger.size());
std::fill(begin(*smaller) + larger.size(), end(*smaller), 0);
}
int dist = 0;
for (unsigned int i = 0; i < hash1.size(); i++) {
dist += (hash1[i] != hash2[i]);
}
return dist;
}
For some reason the hashes returned have different size depending on the input image. I tried to add some padding at getHashDistance() but I don't think I should do that since now when I calculate the distance between two similar images I get a large distance as if they were not similar.
Do you know why that is? I'm resizing the images to 8*8 img.resize(8*8); which I though it would make the trick but it does not work.
Thanks
Thanks

auto imgHash = ImageHash();
Could it be that the auto keyword here is causing the runtime to draw different inferences of the returned type (and therefore the size of the returned type)?
Type Inference in C++ (auto and decltype)

Related

Reference to a vector element become invalid after n iterations

Program stop occur in this line
guess = secret;
From that, I guess that reference is broken, because if I change reference to simple value
const string secret = word_list[idx_word];
the program finishes correctly. So, my question is why this happen. The word_list is not changed/resided in loop.
Erorr occur on 392 iteration.
#include <QCoreApplication>
#include <QFile>
#include <QDir>
#include <QVector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <thread>
#include <mutex>
#include <iomanip>
#include <string>
using namespace std;
bool debug = true;
const int COUNT = 5;
string MASK_FULL_MATCH(COUNT, 'o');
const string getMask(const string& word, const string& answer) {
if (word.size() != COUNT || answer.size() != COUNT) {
cout << word.size() << " " << answer.size() << endl;
}
char mask[5];
bool visited[5];
for (int i = 0; i < COUNT; i++) {
mask[i] = 'x';
visited[i] = false;
}
// find correct letters
for(int i = 0; i < COUNT; i++){
if (word[i] == answer[i]){
mask[i] = 'o';
visited[i] = true;
}
}
// find present letters
for (int i = 0; i < COUNT; i++){
if (mask[i] != 'o'){
for (int j = 0; j < COUNT; j++) {
if (answer[j] == word[i] && !visited[j]) {
mask[i] = '-';
visited[j] = true;
break;
}
}
}
}
return string(mask, COUNT);
}
int main(int argc, char *argv[])
{
QString pathToFile = QString("C:/Users/Ivan/Desktop/w_assets/w") + QString::number(COUNT) + QString("_entropy.txt");
QFile file(pathToFile);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return -2;
QTextStream in(&file);
QVector<string> word_list;
while (!in.atEnd()) {
QString line = in.readLine();
word_list.append(line.split(QChar(' '))[0].toStdString());
}
file.close();
for (int idx_word = 0; idx_word < word_list.size(); idx_word++) {
const string &secret = word_list[idx_word];
cout << secret << '\t';
}
int total = 0;
for (int idx_word = 0; idx_word < word_list.size(); idx_word++) {
const string &secret = word_list[idx_word];
cout << "NEW SECRET " << secret << endl;
QVector<string> possible_answers = word_list;
for (int row = 0; row < 6; row++) {
string guess;
if (row == 0) {
guess = word_list[0];
}
else {
cout << "before broken secret\n";
guess = secret;
cout << "after broken secret\n";
cout << "row " << row << "; GUESS " << guess << endl;
}
debug = true;
string mask = getMask(guess, secret);
debug = false;
cout << "MASK: " << mask << endl;
if (mask == MASK_FULL_MATCH) {
break;
}
QVector<string> new_possible_answers;
for (const auto& pa : possible_answers) {
if (getMask(guess, pa) == mask) {
new_possible_answers.append(pa);
}
}
possible_answers = new_possible_answers;
cout << "NEW POSSIBLE WORDS SIZE " << possible_answers.size() << endl;
}
}
return 0;
}
word_list[0]; - this is a non-const operation in a QVector (see documentation, there is even a note about the possible detach) and since the reference count of your word_list is two due to the copy to possible_answers some lines above, the container has to do a detach and therefore your reference goes out of scope.
If you work with references on Qt containers you have to make sure to either have a reference count of 1 or only use const-access to the container (e.g. by creating a const ref to the container -> const auto &const_word_list = word_list; guess = const_word_list [0])

Is there a way avoid a global array?

A lab assignment that I have for a beginner C++ class involves printing the squareroot of a series of numbers stored in an array. The program itself works, but my teacher does not want us to use global variables.
void assignValue(){
for (int x=0; x<10; x++){
int num;
num = rand() % 100 + 1;
if (num % 2 != 0){
num += 1;
}
arr[x] = num;
}
Here's the main method
int main() {
srand(static_cast<unsigned int>(time(0)));
assignValue();
for (int f = 0; f < 10; f++){
cout << f << setw(8) << right << arr[f];
float square = sqrt(arr[f]);
cout << setw(8) << right << fixed << setprecision(3) << square << endl;
}
The arr is a global variable above the main method.
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <cmath>
void assignValue(int arr[], size_t n) {
for (int i=0; i<n; ++i) {
int num;
num = std::rand() % 100 + 1;
if (num % 2 != 0) {
num += 1;
}
arr[i] = num;
}
}
int main() {
const size_t size = 10;
int arr[size];
std::srand(static_cast<unsigned int>(std::time(0)));
assignValue(arr, size);
for (int i = 0; i < size; ++i){
std::cout << i << std::setw(8) << std::right << arr[i];
float square = std::sqrt(arr[i]);
std::cout << std::setw(8) << std::right << std::fixed << std::setprecision(3) << square << std::endl;
}
return 0;
}
Here is a suggestion for the function taking an array reference:
// headers omitted (you'll need additionally iomanip, ctime, cstdlib, cmath)
// The constant is necessary because the function takes
// a reference to an array *of this specific size*
const size_t ARR_SIZE = 10;
// Take a reference to the array (the array is not copied)
void assignValue(int (&arr)[ARR_SIZE])
{
for (int i = 0; i < ARR_SIZE; i++) {
int num = rand() % 100 + 1;
if (num % 2 != 0) {
num += 1;
}
arr[i] = num;
}
}
You call the function simply with
int main()
{
int arr[ARR_SIZE];
// [...]
assignValue(arr);
// ...
}
The following is a more Core Guideline compliant way of doing this as no pointers, or size information is needed.
#include <cstddef>
#include <cstdlib>
template<typename T, std::size_t N>
void assignValue(T (&arr)[N])
{
for (auto &elem : arr) {
elem = rand() % 100 + 1;
if (elem % 2 != 0) {
elem += 1;
}
}
}
auto
main() -> int
{
constexpr const auto ARRAY_SIZE = 10;
int arr[ARRAY_SIZE];
assignValue(arr);
return 0;
}

which method is more suitable for huffman encoding i want to read chars with their frequency

two loops reading chars from string
void ReadCharWithFreq(string str){
int n = str.size();
int count = 0;
// loops to read all char from string and frequency
for(int i = 0;i<n;i++){
for(int x =0;x<n;x++ ){
if(str[i]==str[x]){
count++;
}
}
//enqueue char with frequency
enqueue(str[i],count);
count=0;
}
} //end of function
same function with different method
using heap array freq[] and memeset
and i dont understand function of memeset(array,int,int)
void ReadCharWithFreq(string str){
int n = str.size();
int SIZE = 40;
int spf=0;
memset(freq, 0, sizeof(freq));
for (int i = 0; i < n; i++){
freq[str[i] - 'a']++;
}
for (int i = 0; i < n; i++) {
if (freq[str[i] - 'a'] != 0) {
cout << str[i] <<" "<< freq[str[i] - 'a'] << " - >";
enqueue(str[i], freq[str[i] - 'a']);
freq[str[i] - 'a'] = 0;
}
}
} //end of function
which one of the above algorithms is more accurate and efficient
i want to read all chars from a string and count their occurrence/frequency
I would use a std::array with space enough to hold the count of all the characters you may encounter:
#include <array>
#include <limits>
constexpr size_t ArrSize = std::numeric_limits<unsigned char>::max()+1;
std::array<unsigned char, ArrSize> ReadCharWithFreq(const std::string& str){
std::array<unsigned char, ArrSize> freq{};
for(unsigned char ch : str)
freq[ch]++;
return freq;
}
Example usage:
#include <iostream>
#include <iomanip>
#include <vector>
int main(int argc, char* argv[]) {
std::vector<std::string> args(argv+1, argv+argc);
for(const auto& str : args) {
auto result = ReadCharWithFreq(str);
for(size_t i=0; i<ArrSize; ++i) {
if(result[i]) {
std::cout << std::setw(3) << i << " " << static_cast<char>(i) << " " << static_cast<int>(result[i]) << "\n";
// enqueue here?
}
}
}
}

C++ Anagram Maker Error

I have been trying to make an anagram maker, using a textBox (encryption_text) for input, which the text is "Hello World", and the output textBox (encrypted_text) which receives the text:
"ellllloooo
WWWWWWooooooorrrrrrrrllllllllldddddddddd".
I also have a textBox called 'anag_used', which should record the used number/location in the string to encrypt.
Have I over complicated it, or is there an error?
Thanks :)
Here is my code:
void anagram()
{
string toanagram = marshal_as<string>(encryption_text->Text);
string out;
int k;
System::String^ rndstr;
System::String^ ktostr;
ostringstream kstr;
anag_used->Clear();
for (int i = 0; i < toanagram.size(); ++i)
{
anag_used->Text += "\n";
int rnd = 0 + rand() % toanagram.size();
ostringstream rndtostr;
rndtostr << rnd;
rndstr = gcnew System::String(rndtostr.str().c_str());
for (int l = 0; l < i; ++l)
{
if (anag_used->Lines[l] == rndstr)
{
k = rnd;
kstr << k;
ktostr = gcnew System::String(kstr.str().c_str());
for (System::String^ j = anag_used->Lines[l]; j == ktostr; k = 0 + rand() % toanagram.size())
{
kstr << k;
ktostr = gcnew System::String(kstr.str().c_str());
if (anag_used->Lines[l] == ktostr)
{
//Do someting if you want
}
else
{
out += toanagram[k];
anag_used->Lines[l] = ktostr;
}
}
}
else
{
out += toanagram[i];
anag_used->Lines[i] = rndstr;
}
}
}
encrypted_text->Text = marshal_as<System::String^>(out);
}
EDIT: FOUND A MUCH SIMPLER WORKING CODE
#include <algorithm>
.
string toanagram = marshal_as<string>(encryption_text->Text);
sort(toanagram.begin(), toanagram.end());
encrypted_text->Text = marshal_as<System::String^>(toanagram);
This works for console, but you could implement it in C++/CLI quite easily
#include <iostream>
#include <sstream>
#include <vector>
#include <ctime>
void str_vect(std::vector<const char>* v, std::string& s)
{
for (int i = 0; i < s.length(); ++i)
{
v->push_back(s[i]);
}
}
int main()
{
for (;;)
{
std::cout << "Please enter the word / phrase\n";
std::string word;
std::getline(std::cin, word);
std::vector<const char> word_split;
str_vect(&word_split, word);
int sz = word_split.size();
std::string anagram;
for (int i = 0; i < sz; ++i)
{
srand(time(NULL));
int r = (rand() % (word_split.size() - 0)) + 0;
anagram += word_split[r];
word_split.erase((word_split.begin()) + r);
}
system("cls");
std::cout << "Please guess the anagrammed phrase / word - '" << anagram << "'\n";
int max_tries = 3;
int tries = max_tries;
for (int i = 0; i <= max_tries; ++i)
{
std::string guess;
std::getline(std::cin, guess);
if (guess != word)
{
tries--;
if (tries == 0)
{
std::cout << "You have ran out of tries. The answer was: " << word << "\n";
break;
}
std::cout << tries << ((tries == 1) ? " try" : " tries") << " left\n";
}
else
{
std::cout << "Correct!\n";
break;
}
}
}
}
#include <algorithm>
.
string toanagram = marshal_as<string>(encryption_text->Text);
sort(toanagram.begin(), toanagram.end());
encrypted_text->Text = marshal_as<System::String^>(toanagram);

Converting string of 1s and 0s into binary value

I'm trying to convert an incoming sting of 1s and 0s from stdin into their respective binary values (where a string such as "11110111" would be converted to 0xF7). This seems pretty trivial but I don't want to reinvent the wheel so I'm wondering if there's anything in the C/C++ standard libs that can already perform such an operation?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char * ptr;
long parsed = strtol("11110111", & ptr, 2);
printf("%lX\n", parsed);
return EXIT_SUCCESS;
}
For larger numbers, there as a long long version, strtoll.
You can use std::bitset (if then length of your bits is known at compile time)
Though with some program you could break it up into chunks and combine.
#include <bitset>
#include <iostream>
int main()
{
std::bitset<5> x(std::string("01011"));
std::cout << x << ":" << x.to_ulong() << std::endl;
}
You can use strtol
char string[] = "1101110100110100100000";
char * end;
long int value = strtol (string,&end,2);
You can use Boost Dynamic Bitset:
boost::dynamic_bitset<> x(std::string("01011"));
std::cout << x << ":" << x.to_ulong() << std::endl;
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
string getBinaryString(int value, unsigned int length, bool reverse) {
string output = string(length, '0');
if (!reverse) {
for (unsigned int i = 0; i < length; i++) {
if ((value & (1 << i)) != 0) {
output[i] = '1';
}
}
}
else {
for (unsigned int i = 0; i < length; i++) {
if ((value & (1 << (length - i - 1))) != 0) {
output[i] = '1';
}
}
}
return output;
}
unsigned long getInteger(const string& input, size_t lsbindex, size_t msbindex) {
unsigned long val = 0;
unsigned int offset = 0;
if (lsbindex > msbindex) {
size_t length = lsbindex - msbindex;
for (size_t i = msbindex; i <= lsbindex; i++, offset++) {
if (input[i] == '1') {
val |= (1 << (length - offset));
}
}
}
else { //lsbindex < msbindex
for (size_t i = lsbindex; i <= msbindex; i++, offset++) {
if (input[i] == '1') {
val |= (1 << offset);
}
}
}
return val;
}
int main() {
int value = 23;
cout << value << ": " << getBinaryString(value, 5, false) << endl;
string str = "01011";
cout << str << ": " << getInteger(str, 1, 3) << endl;
}