How convert text to pixel array in QT - c++

I'm new user of QT. Is it possible to convert for example one character or string to array where 0 means white field and 1 means black field? For example when I have character "a" saved as QString or any representation of font and I would like to get following array:
int array[9][6] = { //"a" char array
{0, 0, 0, 0, 0, 0}, //- - - - - -
{0, 1, 1, 1, 1, 0}, //- * * * * -
{1, 0, 0, 0, 0, 1}, //* - - - - *
{0, 0, 0, 0, 0, 1}, //- - - - - *
{0, 1, 1, 1, 1, 1}, //- * * * * *
{1, 0, 0, 0, 0, 1}, //* - - - - *
{1, 0, 0, 0, 1, 1}, //* - - - * *
{0, 1, 1, 1, 0, 1}, //- * * * - *
{0, 0, 0, 0, 0, 0}, //- - - - - -
};
Is there any way in QT for reach that goal ? I hope I describe my problem as clear as possible and someone can help me with this?
And very important thing size array must depend on selected font size, so if I choose for example 30 pt font, array should be appropriate bigger than 10 pt font.
Thank You very much.
Best regards.

You can draw text onto a bitmap image, which will give you a bitmap containing text. Which is a pixel array, for all intents and purposes.
Note that you will also have to use a "bitmap font", regular fonts won't really do the trick as most have been created to utilize antialiasing and won't result in a crisp and readable bitmap image.
Qt also offers font metrics, which can give you a clear idea how big text or individual characters are.

I misinterpreted the question on my first read through... well, here is what was asked for...
#include <QApplication>
#include <QPixmap>
#include <QLabel>
#include <QPainter>
#include <QDebug>
#include <QVector>
#include <QFontMetrics>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSize size;
// QPixmap pixmap(100,100);
QImage image(20,20, QImage::Format_Mono);// Change the width and height here as needed if your letters get too big
image.fill(0);
{
QPainter painter(&image);
//// alternative to fill method
// painter.setBrush(Qt::black);
// painter.drawRect(0,0,image.width(), image.height());
painter.setPen(Qt::white);
QFontMetrics fm(painter.font());
size.setHeight(fm.height());
size.setWidth(fm.width('a'));
painter.drawText(0,fm.height(),"a");
}
QLabel label;
label.setPixmap(QPixmap::fromImage(image).scaled(400,400, Qt::KeepAspectRatio));
label.show();
QVector <QVector <int> > array(size.height(), QVector < int> (size.width(), 0));
for(int r = 0; r < size.height(); r++)
for(int c = 0; c < size.width(); c++)
array[r][c] = (image.pixelColor(c,r) == Qt::white ? 1 : 0);
// qDebug() << size << array;
foreach(QVector <int> row, array)
qDebug() << row;
return a.exec();
}
Output:
QVector(0, 0, 0, 0, 0, 0)
QVector(0, 0, 0, 0, 0, 0)
QVector(0, 0, 0, 0, 0, 0)
QVector(0, 0, 0, 0, 0, 0)
QVector(0, 0, 0, 0, 0, 0)
QVector(0, 0, 0, 0, 0, 0)
QVector(0, 0, 0, 0, 0, 0)
QVector(0, 1, 1, 1, 0, 0)
QVector(0, 0, 0, 0, 1, 0)
QVector(0, 1, 1, 1, 1, 0)
QVector(1, 0, 0, 0, 1, 0)
QVector(1, 0, 0, 0, 1, 0)
QVector(0, 1, 1, 1, 1, 0)

Related

I want to know how to add names to the edges? I'm new with Dijkstra algorithm

I'm suppose to to give the shortest path from one place to another. I'm totally new with this, so I'm starting small. Just like 10 intersections around my place. However, I got how to print out the path from one place to another. I'm trying to figure out how to assign the names to this edges. And I don't know if using adjacency matrix is the best option. What if I have more than 100 nodes? How can I do it?
// A C++ program for Dijkstra's single source shortest path algorithm.
// The program is for adjacency matrix representation of the graph
#include <iostream>
#include <limits.h>
#include <iomanip>
using namespace std;
// Number of vertices in the graph
#define V 14
// A utility function to find the vertex with minimum distance value, from
// the set of vertices not yet included in shortest path tree
int minDistance(int dist[], bool sptSet[])
{
// Initialize min value
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (sptSet[v] == false && dist[v] <= min)
min = dist[v], min_index = v;
return min_index;
}
void printPath(int parent[], int j)
{
// Base Case : If j is source
if (parent[j] == -1)
return;
printPath(parent, parent[j]);
cout << " --> " << j;
}
// A utility function to print the constructed distance array
void printSolution(int dist[], int n, int parent[])
{
printPath(parent, n);
cout << "\nThe distance from Source to Destination is: "<< dist[n] << endl;
}
// Function that implements Dijkstra's single source shortest path algorithm
// for a graph represented using adjacency matrix representation
void dijkstra(int graph[V][V], int src, int destination)
{
int dist[V]; // The output array. dist[i] will hold the shortest distance from src to i
bool sptSet[V]; // sptSet[i] will be true if vertex i is included in shortest path tree or shortest distance from src to i is finalized
int parent[V]; // Parent array to store shortest path tree
// Initialize all distances as INFINITE and stpSet[] as false
for (int i = 0; i < V; i++) {
dist[i] = INT_MAX;
sptSet[i] = false;
parent[i] = -1;
}
// Distance of source vertex from itself is always 0
dist[src] = 0;
// Find shortest path for all vertices
for (int count = 0; count < V - 1; count++)
{
// Pick the minimum distance vertex from the set of vertices not
// yet processed. u is always equal to src in the first iteration.
int u = minDistance(dist, sptSet);
if (u == destination)
break;
// Mark the picked vertex as processed
sptSet[u] = true;
// Update dist value of the adjacent vertices of the picked vertex.
for (int v = 0; v < V; v++)
// Update dist[v] only if is not in sptSet, there is an edge from
// u to v, and total weight of path from src to v through u is
// smaller than current value of dist[v]
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
parent[v] = u;
dist[v] = dist[u] + graph[u][v];
}
}
// print the constructed distance array
cout << "From " << src;
printSolution(dist, destination, parent);
}
// driver program to test above function
int main()
{
/* Let us create the example graph discussed above */
int graph[V][V] = { {0, 5, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0},
{5, 0, 6, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0},
{0, 6, 0, 3, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 3, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 7, 0, 4, 0, 0, 0, 0, 0, 0, 0, 7},
{0, 0, 7, 0, 4, 0, 4, 0, 0, 0, 0, 0, 6, 0},
{0, 8, 0, 0, 0, 4, 0, 4, 0, 0, 0, 5, 0, 0},
{0, 0, 0, 0, 0, 0, 4, 0, 3, 0, 4, 0, 0, 0},
{8, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 4, 0, 3, 0, 4, 0, 0},
{0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 4, 0, 4, 0},
{0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 4, 0, 4},
{0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 4, 0}
};
dijkstra(graph, 0, 13);
return 0;
}

C++ SFML: How to successfully Iteratively render shapes?

I'm looking to iteratively create a set of rectangle shapes of different colours and display them on the screen in different positions. This should produce a maze made up of rectangles.
The positions of the shapes should reflect the array that stores a 9x9 maze.
I'm able to successfully create a single shape, change it's colour and position. However, when I try to do the same to a shape inside an array it does not work. Only a single blue rectangle is generated in the top right corner of the screen.
int main() {
sf::RenderWindow window(sf::VideoMode(1920, 1080), "Baphomet");
sf::RectangleShape tiles[81] = {sf::RectangleShape(sf::Vector2f(20, 20))};
char maze[81] = {0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 1, 0, 1, 1, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 1, 1, 0, 1, 0, 1, 0,
0, 0, 0, 1, 0, 1, 0, 1, 0,
0, 1, 1, 1, 0, 1, 1, 1, 0,
0, 0, 1, 0, 0, 0, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0};
int x;
int y;
for (int i = 0; i < 81; i++) {
if (maze[i] == 0) {
tiles[i].setFillColor(sf::Color::Blue);
} else if (maze[i] == 1) {
tiles[i].setFillColor(sf::Color::Red);
}
x = (i % 9) * 20;
y = (i / 9) * 20;
std::cout << x << " " << y << std::endl;
tiles[i].setPosition((float)x, (float)y);
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
for (int i = 0; i < 81; i++) {
window.draw(tiles[i]);
}
window.display();
}
return 0;
}
How can I make the shapes change their positions to the x and y variables successfully?
I think the main problem is the definition
sf::RectangleShape tiles[81] = {sf::RectangleShape(sf::Vector2f(20, 20))};
Here you explicitly initialize only the first element (tiles[0]). All the rest of the elements will only have default-constructed shape objects.
To properly initialize all elements to the same values, either use a loop
for (auto& shape : tiles)
shape = sf::RectangleShape(sf::Vector2f(20, 20));
Or use a vector
std::vector<sf::RectangleShape> tiles(81, sf::RectangleShape(sf::Vector2f(20, 20)));

How to change the color of each pixel of image using openCV [duplicate]

This question already has answers here:
How to fill OpenCV image with one solid color?
(9 answers)
Closed 4 years ago.
I am new in OpenCV. I have a image what I want is to change the color of each and every pixel of image with any single color.
I found that code but when I run this part of code then a exception is generated.
for (i = 0;i < img1.rows;i++) {
for (j = 0;j < img1.cols;j++) {
img1.at<Vec3b>(i, j) = Vec3b(255, 105, 240);
}
}
Can anyone please tell me the solution.
Or what I found is that this take a lot of time for the conversion So if their is any other approach then please tell me.
// Make a 3 channel image
cv::Mat img(480,640,CV_8UC3);
// Fill entire image with cyan (blue and green)
img = cv::Scalar(255,255,0);
You can use Mat::operator() to select the roi and then assign a value to it.
void main()
{
cv::Mat img = cv::Mat::ones(5, 5, CV_8UC3);
img({2, 4}, {2, 4}) = cv::Vec3b(7, 8, 9);
cout << img;
}
This will print
[ 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0;
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0;
1, 0, 0, 1, 0, 0, 7, 8, 9, 7, 8, 9, 1, 0, 0;
1, 0, 0, 1, 0, 0, 7, 8, 9, 7, 8, 9, 1, 0, 0;
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0]
To fill image with single color, use rectangle with CV_FILLED argument.
(there might be some reasons for exception - image was not created, wrong pixel format etc - it is hard to diagnose a problem with given information)

The safest way to add integer into array value without having to call it?

What is the safest way to add integer into array value without having to call the array value ? In this case I would rather not to call the array value because the array is inside a nested loop and the loop itself can repeat for thousands times.
For example dots[1] = I want to add value of this array with 3. Here's my sample code :
void box(const Mat &dots, Mat &newdots, int rows, int cols)
{
for (int i = 0; i < dots.rows; i++) {
for (int j = 0; j < dots.cols; j++) {
newdots.at<Vec3b>(i, j)[0] = dots.at<Vec3b>(i, j)[0];
newdots.at<Vec3b>(i, j)[1] = dots.at<Vec3b>(i, j)[1]; //add this with 3
newdots.at<Vec3b>(i, j)[2] = dots.at<Vec3b>(i, j)[2]; //add this with 5
}
}
Is it possible ? Any suggestion how to do it ? Thanks.
This simplest way is to use cv::add, which overloads the + operator for the Mat class:
// Create a Mat of all 0's
cv::Mat dots = cv::Mat(5, 4, CV_8UC3, cv::Scalar(0,0,0));
std::cout << "dots:\n" << dots << std::endl;
// Add 0 to the B channel, 3 to the G channel, and 5 to R
cv::Mat newdots = dots + cv::Scalar(0, 3, 5);
std::cout << "newdots:\n" << newdots << std::endl;
Result:
dots:
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
newdots:
[ 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5;
0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5;
0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5;
0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5;
0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5]
Note that dots += Scalar(0,3,5) also works if you just want to modify the original Mat.

How can I properly pass sprites to a std::Vector without destroying their texture?

From the official SFML tutorials, The White Box Problem:-
"When you set the texture of a sprite, all it does internally is store a pointer to the texture instance. Therefore, if the texture is destroyed or moves elsewhere in memory, the sprite ends up with an invalid texture pointer." Thus a sprite without a texture will be seen.
I have a class called World. In this class I made a 2d integer array called level and a vector of type Block called blocks. Now I wanted to store the 'Block' objects inside the vector whenever level[ i ][ j ] = 1.
header file of the 'World' class:-
#ifndef WORLD_H
#define WORLD_H
#include <vector>
#include "Block.h"
#include "Grass.h"
#include <SFML/Graphics.hpp>
using namespace std;
class World
{
public:
World();
void draw(sf::RenderWindow *window);
vector<Block> blocks;
private:
int level[12][16];
int wd;
int hi;
};
#endif // WORLD_H
cpp file of the 'World' class :-
#include "World.h"
#include "Grass.h"
#include "Block.h"
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
World::World() : level{
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
}
{
wd = 16;
hi = 12;
int count = 1;
//make a 'Block' object and pass it in the vector when level[ i ][ j ] = 1.
for(int i = 0; i<hi; i++)
{
for(int j = 0; j<wd; j++)
{
if(level[i][j] == 1)
{
Block block(j*50, i*50);
blocks.push_back(block);
}
}
}
}
void World::draw(sf::RenderWindow *window)
{
for(unsigned int i = 0; i<blocks.size(); i++)
{
blocks[i].draw(window);
}
}
The 'Block' class has two members - sf::Texture blockT and sf::Sprite block. It also has a draw(RenderWindow *window) method. This is how the 'Block' class is made :-
header file for block class
#ifndef BLOCK_H
#define BLOCK_H
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
class Block
{
public:
Block(float x, float y);
void draw(sf::RenderWindow *window);
private:
sf::Texture blockT;
sf::Sprite block;
};
#endif // BLOCK_H
cpp file for 'Block' class
#include "Block.h"
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
Block::Block(float px, float py)
{
if(!(blockT.loadFromFile("textures/block.png")))
{
cout<<"Could not load block texture."<<endl;
}
block.setTexture(blockT);
block.setPosition(sf::Vector2f(px, py));
cout<<px<<endl;
cout<<py<<endl;
}
void Block::draw(sf::RenderWindow *window)
{
window->draw(block);
}
When I run the program, in place of blocks, only white box is shown. I don't understand how the texture is getting destroyed. This is what the output looks like :-
As you can see, the white places are sprites each of size 50*50 without any texture.
You should customise copy-construction of blocks so it updates the texture pointer, something like:
Block::Block(const Block& other)
: blockT(other.blockT), block(other.block)
{
block.setTexture(blockT);
}
That will be used when push_back() in the vector forces a resize, and the newly allocated, larger buffer's elements are copy-constructed from the old elements before the latter are "destructed" and deallocated.
It would be a good idea to support the same kind of update for assignment, i.e. operator=(const Block& rhs).
Regarding your "Thus a sprite without a texture will be seen." - it's much more likely that the behaviour is undefined since you're effectively following a pointer to released memory that could get corrupted with new content at any time, and happens to manifest as a lack of texture currently in your testing, but might crash and burn at some other optimisation level, after some minor code changes, on another compiler or OS etc..
Your solution of having a Block class which stores its own instance of an sf::Texture is going to cause you to have duplicate copies of textures hanging around in memory. It's also going to require you to learn and follow the rule of three when you're dealing with your Block objects as per Tony D's answer.
The simpler solution is to have a separate std::map of filenames to sf::Textures into which you can load the textures that you require once, and retrieve everywhere you need them.
// Have one of these, maybe as a member of your World class?
std::map<std::string,sf::Texture> textures;
// load your textures into it ...
Then in your Block class ...
class Block
{
public:
// constructor now takes a reference to a texture map ...
Block(float x, float y,std::map<std::string,sf::Texture>& textures);
And in the implementation you can retrieve the texture you want by its filename, and assign it t the sprite with setTexture.