Why declaring a QImage as static const produces an invalid value? - c++

I have a QGraphicsItem object called ItemView which I am creating many instances of, and they all show up as a QImage on my QGraphicsView.
I have it working by creating a new QImage for each instance of ViewItem, but now I'm trying to convert that property to a static field to optimize because I really only need one, and I just cant get it to work.
As a test I added a static const int next to the QImage and that works just fine.
// .hh
class ViewItem : public QGraphicsItem
{
public:
...
private:
static const QImage IMAGE;
static const int TEST;
};
//.cc
const QImage ViewItem::IMAGE = QImage(":/data/data/img.png");
const int ViewItem::TEST = 30;
breakpoint in my QGraphicsItem::paint() method shows IMAGE value as (invalid) but TEST shows 30 as expected.
Why is it working for int but not QImage?

Note: For me this is a XY problem. I will provide a solution to the X problem and I suggest you to think about your Y problem and probably ask another question, which targets it explicitly.
Cause
You initialize ViewItem::IMAGE with a QImage, constructed from a fileName. As per documentation:
If the loading of the image failed, this object is a null image.
The loading fails, because the resource file is not available at the time, at which ViewItem::IMAGE is initialized.
Solution to X
To get the expected result, instead of a resource image, use an image from the disk, located in the data/data/ subfolder with respect to the build folder:
const QImage ViewItem::IMAGE = QImage("data/data/img.png");
The image would exist at the time of the initialization, so the constructor would succeed to create a valid QImage. To test this, call:
qDebug() << TEST << IMAGE;
in the constructor of ViewItem. It would produce a similar result:
30 QImage(QSize(256, 256),format=QImage::Format_ARGB32,depth=32,devicePixelRatio=1,bytesPerLine=1024,sizeInBytes=262144)

Related

How to call a function for specific objects in a C++ Array?

I hope you can help me because I'm trying to improve my C++ inheritance concepts. First of all, I have the following object hierarchy:
A base class "Image" with two child classes: PNG and JPG (each one with their methods).
I wrote a method inside PNG class which (in a simulated way) deletes alpha channel (it just prints "Alpha channel deleted").
That being said, I want to write a method which takes an array of many pointers to image objects (can be either JPG or PNG) as input, and deletes the alpha channel of only those which are PNG. Since it isn't a good practice in C++ ask for the type of the object (or so I believe), which is the best way to loop through the image array (remembering that it could be filled with either PNG or JPG objects) and delete the alpha channel of only the PNG objects? In which class should I write that method? Parent or child?
I hope I've explained myself correctly, and thank you very much in advance.
The obvious implementation is that the base class has a virtual method for deleting the alpha channel that is a no-op. The PNG class inherits from Image and overrides this member function.
class Image
{
public:
virtual void DeleteAlphaChannel() {};
};
class PNG : public Image
{
void DeleteAlphaChannel() override
{
cout << "Alpha Channel deleted" << endl;
}
};
Then a helper function that takes an array of Image pointers, hence Image**
void DeleteAlphaChannelsFromArrayOfObjects(Image** imageList, int count)
{
for (int i = 0; i < count; i++)
{
imageList[i]->DeleteAlphaChannel();
}
}
And corresponding sample code.
{
PNG pngFile("foo.png");
JPG jpgFile("bar.jpg");
Image* imageList[2] = {&pngFile, &jpgFile};
DeleteAlphaChannelsFromArrayOfObjects(imageList, 2);
}
You could also do a vector style implementation:
void DeleteAlphaChannelsFromArrayOfObjects(std::vector<Image*>& imageList)
{
for (Image* pImage : images)
pImage->DeleteAlphaChannel();
}

Static Polymorphism Issue

I am on a micro controller (which means I can only have static memory allocation) and I am trying to work with inheritance.....
Suppose I have a abstract class Image and an abstract class Font. An instance of Font can return an Image based off of the char given in a function like so:
Font* mf;
Image* image = mf->GetImage("a");
Now the real issue is I have no idea what to do for the GetImage Function.
The problem is this: in c++ for you to have a member of an abstract class you have to use it as a pointer. So my dilemma is that I have a Font which wants to create a new Image and then return it.
If it returns a pointer to its newly created Image you are returning a reference to a temporary object:
Image* FontImpl::GetImage(char c){
return &ImageImpl(c); //This object is destroyed once this function exits
}
And then if I return I try to return an actual type like this:
Image FontImpl::GetImage(char c){
return ImageImpl(c); //Cannot cast from ImageImpl to Image
}
So is there an idiom or something for this kind of static memory problem?
Using dynamic allocation would be easiest but if that's not possible, you have to store the instance somewhere outside the function, e.g.:
static ImageImpl image;
Image& FontImpl::GetImage(char c) {
image = ImageImpl(c);
return image;
}

Using private static variable across multiple classes

I've a class for my one of programs which is drawing image sequences at different positions on the window. The class has multiple instances but it's the same image sequence which is being drawn at all the positions inside the window. I want to prevent multiple instances of class initializaing multiple image sequences to avoid eating memory, for which I have the image sequence variable as static variable
class Drawer{
private:
static ImageSequence imgSequence;
};
In the .cpp file, I am doing the following to initialize the static var.
#include "Drawer.h"
ImageSequence Drawer::imgSequence = ImageSequence();
However, I have two methods to specify the path to image sequences and preload al frames - and confused about where to put these methods so that each Drawer class instantiation does not preload the frames time and again. How'd this be done in C++?
--EDIT
The two methods as asked for: i) loadSequence, ii)preloadAllFrames();
loadSequence(string prefix, string firstFrame, string lastFrame){
for(int i=0;i<numFrames;++i){
//adds and pushes values of all the files in the sequence to a vector
}
}
preloadAllFrames(){
for(int i=0;i<numFrames;++i){
//create pointers to image textures and store then in a vector so that it doesn't take time to load them for drawing
}
}
Have an accompanying boolean value with the image and check if the image has been already loaded when you try to load it. You can also load it when your program is initializing only once instead of attempting to load it every frame.
Just have a static pointer instead of instance and initialize in a static method:
class Drawer{
private:
static std::unique_ptr<ImageSequence> imgSequence;
public:
static void initializeMethod1()
{
if( imgSequence ) return; // or throw exception
imgSequence.reset( new ImageSequence( ... ) );
...
}
static void initializeMethod2() {}
{
if( imgSequence ) return; // or throw exception
imgSequence.reset( new ImageSequence( ... ) );
...
}
static ImageSequence &getSequence()
{
if( !imgSequence ) throw std::runtime_error( "image sequence is not intialized" );
return *imgSequence;
}
};

How to pass an Image in SFML C++

I am trying to make a simple function or class that selects an image and returns it or passes it in some way to a different class. Is it as simple as knowing what type the Image is considered? or do I need to do something else? I am running Code::Blocks 10.05 with GNU GCC compiler on a windows 8 computer. Any help is appreciated.
Thanks to Aesthete, I made some progress. Now I have this:
class Background{
sf::Image BGI;
sf::Sprite BG;
Image& img;
public:
void rimage(std::string name){
sf::Image extra;
extra.LoadFromFile(name);
img = extra;
}
void init(std::string name){
BGI = img
BG.SetPosition(0.f,0.f);
BG.SetImage(BGI);
}
};
But when I run it, I get this:
...4 error: ISO C++ forbids declaration of 'Image" with no type
Also,
...10 error: 'img' is defined in this scope
I have included the libraries that I need to run SFML, I just left it out to keep things clean, I adjusted the lines the errors above occurred on to make it easier to follow.
Isn't img now sort of a global variable within Background?
and I thought Image& was the type of img... What needs to change here?
You don't need a load method, nor any extra Image objects. You can do all this processing in the constructor.
class Background{
private:
// You only need an image and a background, if that.
sf::Image BGI;
sf::Sprite BG;
public:
// Use a constructor.
Background(std::string name)
{
SetBackground(name, Vector2f(0.f, 0.f));
}
void SetBackground(std::string name, sf::Vector2f pos)
{
BGI.LoadFromFile(name);
BG.SetImage(BGI);
BG.SetPosition(pos);
}
};
// Constructor loads image, sets image to sprite, and set sprite position.
Background bg("MyBackground.png");
// You can change the background image an position like so.
bg.SetBackgrond("newImage.png", Vector2f(10.f, 20.f));

OpenCV trackbar callback in C++ class

I have a question about how to define the callback for trackbars in OpenCV when working with classes in C++.
When I define my trackbar let's say in the constructor method of my .cpp class how can I define the callback?
I have been trying to work with function pointers but it doesn't work out. I guess I must be doing something very wrong :-)
This is my header file:
class SliderwithImage {
public:
SliderwithImage(void);
~SliderwithImage(void);
void sliderCallBack(int pos);
};
This is the implementation file:
#include "SliderwithImage.h"
void SliderwithImage::sliderCallBack(int pos) {
}
SliderwithImage::SliderwithImage(void) {
const char* windowName = "window";
int lowvalue =1;
namedWindow(windowName, CV_GUI_EXPANDED);
createTrackbar("mytrackbar", windowName, &lowvalue, 255, sliderCallBack);
}
SliderwithImage::~SliderwithImage(void) {
}
Obviously the createTrackbar method does not recognize sliderCallBack... I guess it's a problem of scope. But I am not sure how to solve this?
Any help would be appreciated.
Thank you very much.
The callback function must be static or global, but you can pass it a reference to an object you want to operate on (see this post on the OpenCV Users mailing list).
The createTrackbar method has a userdata parameter which is passed to the calling function. In C there is an undocumented cvCreateTrackbar2 method, defined in highgui_c.h, which has the same functionality:
CVAPI(int) cvCreateTrackbar2( const char* trackbar_name, const char* window_name,
int* value, int count, CvTrackbarCallback2 on_change,
void* userdata CV_DEFAULT(0));
These methods let you create a class with a static callback function that takes a pointer to an object of that class. You can create the trackbar like so:
cv:createTrackbar("Label", "Window" &variable, MAX_VAL, &MyClass::func, this);
The callback would look something like this:
void MyClass:func(int newValue, void * object) {
MyClass* myClass = (MyClass*) object;
// ...do stuff.
}
Note that you don't need to explicitly update the variable yourself as long as you provided a pointer to it when creating the trackbar (as above), but if you need to process it first I suggest you set it explicitly in the callback function.
You have to implement the callback function either as a global function or a static member function. To make it more OOP look, you might prefer to implement it as a static member function:)
I am using a different solution to obtain the slider value in a class variable (in my case to obtain chosen rotation angle of a live video stream). The int* value in the createTrackbar function is a public class variable which is then used within a loop (while the video is acquired, but this might messily work repeatedly redrawing a single image).
Not the best solution but it works for me.
cv::createTrackbar("Rotation Angle(deg)", "Preview", &rotationAngle,
alpha_slider_max, NULL);
for(;;)
{
int rotAngle = this -> rotationAngle;
cv::Mat frame;
cv::Mat rot_frame;
this -> capture >> frame;
rot_frame = rotateVideo (frame, rotAngle);
imshow("Preview", rot_frame);
if(cv::waitKey(30) >= 0) break;
}