Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
How can someone use Qt for image processing? Are there libraries or plugins for Qt for this purpose?
Thanks.
Qt is rather meant for developing graphical user interfaces (GUIs). However, it comes with a lot of supplementary libraries, including one dedicated to image processing. However, if you want to get serious, I would recommend a dedicated library such as OpenCV.
I did use Qt for GUI plus LTIlib for image processing.
Qt itself won't be very helpful for processing any image, but there are a couple of independent libraries that you can use best fitting your needs. Bear in mind that Qt is essentially meant to be a GUI framework. It is very very good, if not the best, to make windows, buttons, tree views, etc. but don't expect it to be so comprehensive that can do everything.
Please let us to know more preciselly what you mean when you say "image processing".
It is a vast reign with hundreds or thousands of possible goals and approaches...
EDIT:
Here is a small excerpt or what I used to do with Qt+LTI.
See LTI documentation for all operators available. I used to do convolutions, self-correlations, basic erosion/dilation and a lot more.
#include <ltiDilation.h>
#include <ltiErosion.h>
#include <ltiBinaryKernels.h>
#include <ltiFastRelabeling.h>
#include <ltiLabelAdjacencyMap.h>
void QLTIDialog::init()
{
viewLayout = new QGridLayout( frmView, 1, 1, 4, 4, "viewLayout" );
view= new QImageLabel( frmView, "view" );
viewLayout->addWidget( view, 0, 0 );
frmView->setUpdatesEnabled( false );
view->image( &qimg );
}
void QLTIDialog::btnOpen_clicked()
{
QString fn= QFileDialog::getOpenFileName(
"",
tr( "All files (*.*)" ),
this,
tr( "Open image" ),
tr( "Select image file" ) );
if ( !fn.isEmpty( ) )
{
if ( !qimg.load( fn ) )
{
QMessageBox::critical( this, tr( "Fatal error" ),
QString( tr( "Unable to open %1" ) ).arg( fn ),
tr( "Exit" ) );
return;
}
view->update( );
setCaption( fn );
}
}
void QLTIDialog::btnProcess_clicked()
{
lti::image img;
lti::channel8 tmp0,
h, s, v;
// Taking QImage data, as in the wiki.
img.useExternData( qimg.width( ), qimg.height( ), ( lti::rgbPixel * )qimg.bits( ) );
// Converting to HSV gives-me best results, but it can be left out.
lti::splitImageToHSV hsv;
hsv.apply( img, h, s, v );
// I do some manipulation over the channels to achieve my objects positions.
lti::maskFunctor< lti::channel8::value_type > masker;
masker.invert( v, tmp0 );
masker.algebraicSum( s, tmp0 );
// Show the resulting processed image (ilustrative)...
QLTIDialog *dh= new QLTIDialog;
dh->showImage( tmp0 );
// Apply relabeling (example). Any other operator can be used.
lti::fastRelabeling::parameters flPar;
flPar.sortSize= true;
flPar.minimumObjectSize= 25;
flPar.fourNeighborhood= true;
flPar.minThreshold= 40;
lti::fastRelabeling fr( flPar );
fr.apply( tmp0 );
lti::image imgLam;
lti::labelAdjacencyMap lam;
lam.apply( tmp0, imgLam );
// By hand copy to QImage.
lti::image::iterator iit= imgLam.begin( );
lti::rgbPixel *pix= ( lti::rgbPixel * )qimg.bits( );
for ( ; iit != imgLam.end( ); ++iit, ++pix )
*pix= *iit;
view->update( );
}
void QLTIDialog::showImage( lti::image &img )
{
qimg= QImage( reinterpret_cast< uchar * >( &( *img.begin( ) ) ),
img.rows( ), img.columns( ), 32, ( QRgb * )NULL,
0, QImage::LittleEndian ).copy( );
QDialog::show( );
}
void QLTIDialog::showImage( lti::channel8 &ch )
{
lti::image img;
img.castFrom( ch );
qimg= QImage( reinterpret_cast< uchar * >( &( *img.begin( ) ) ),
img.rows( ), img.columns( ), 32, ( QRgb * )NULL,
0, QImage::LittleEndian ).copy( );
QDialog::show( );
}
EDIT Again:
I found another sample that may be more interesting to you...
lti::image img;
lti::channel8 chnl8( false, imgH, imgW ), h, s, v;
// Pass image data to LTI.
img.useExternData( imgH, imgW, ( lti::rgbPixel * )pixels );
// I got better results in HSV for my images.
lti::splitImageToHSV hsv;
hsv.apply( img, h, s, v );
// Segmentation.
lti::channel8::iterator it= chnl8.begin( );
lti::channel8::iterator hit= h.begin( ),
sit= s.begin( ),
vit= v.begin( );
for ( ; it != chnl8.end( ); ++it, ++hit, ++sit, ++vit )
{
int tmp= *sit * 2;
tmp-= *hit - 320 + *vit;
*it= ( *hit > 40 && tmp > 460 ? 1 : 0 );
}
// Distinguish connected objects.
lti::imatrix objs;
std::vector< lti::geometricFeatureGroup0 > objF;
lti::geometricFeaturesFromMask::parameters gfPar;
gfPar.merge= true; // Join close objects.
gfPar.minimumDistance= lti::point( 24, 24 );
gfPar.minimumMergedObjectSize= 2; // Exclude small ones.
gfPar.nBest= 800; // Limit no. of objects.
lti::geometricFeaturesFromMask gf( gfPar );
gf.apply( chnl8, objs, objF );
points.clear( );
for( std::vector< lti::geometricFeatureGroup0 >::const_iterator gfg0= objF.begin( );
gfg0 != objF.end( ); ++gfg0 )
points.push_back( Point( gfg0->cog.x, gfg0->cog.y ) );
The rest is like the first example.
Hope it helps.
Image processing is a rather generic term. Have a look at VTK and ITK from Kitware. Also Freemat (a Matlab clone) is based on Qt. Qt is popular among quantitative scientists, I expect that there quite a few Qt-based imaging libraries and products.
I use QT for image Processing. I use OpenCV then I convert the OpenCV Mat into a QImage, then I display it in a label on the UI.
Thank you
Related
void bundleAdjustment ( const vector< cv::Point3f > points_3d,
const vector< cv::Point2f > points_2d,
const Mat& K, Mat& R, Mat& t )
{
typedef g2o::BlockSolver< g2o::BlockSolverTraits<6,3> > Block;
Block::LinearSolverType* linearSolver = new g2o::LinearSolverCSparseBlock::PoseMatrixType();
Block* solver_ptr = new Block ( linearSolver );
g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg ( solver_ptr );
g2o::SparseOptimizer optimizer;
optimizer.setAlgorithm ( solver );
g2o::VertexSE3Expmap* pose = new g2o::VertexSE3Expmap(); // camera pose
Eigen::Matrix3d R_mat;
R_mat <<
R.at<double> ( 0,0 ), R.at<double> ( 0,1 ), R.at<double> ( 0,2 ),
R.at<double> ( 1,0 ), R.at<double> ( 1,1 ), R.at<double> ( 1,2 ),
R.at<double> ( 2,0 ), R.at<double> ( 2,1 ), R.at<double> ( 2,2 );
pose->setId ( 0 );
pose->setEstimate ( g2o::SE3Quat (R_mat,
Eigen::Vector3d ( t.at ( 0,0 ), t.at ( 1,0 ), t.at ( 2,0 ) ) ) );
optimizer.addVertex ( pose );
int index = 1;
for (const Point3f p:points_3d ) // landmarks, world coordinates.
{
g2o::VertexSBAPointXYZ* point = new g2o::VertexSBAPointXYZ();
point->setId ( index++ );
point->setEstimate ( Eigen::Vector3d ( p.x, p.y, p.z ) );
point->setMarginalized ( true );
optimizer.addVertex ( point );
}
g2o::CameraParameters* camera = new g2o::CameraParameters (K.at<double> ( 0,0 ), Eigen::Vector2d ( K.at<double> ( 0,2 ), K.at<double> ( 1,2 ) ), 0);
camera->setId ( 0 );
optimizer.addParameter ( camera ); //Add camera parameters
index = 1;
for ( const Point2f p:points_2d ) //Add edges(observed data)
{
g2o::EdgeProjectXYZ2UV* edge = new g2o::EdgeProjectXYZ2UV();
edge->setId ( index );
edge->setVertex ( 0, dynamic_cast<g2o::VertexSBAPointXYZ*> ( optimizer.vertex ( index ) ) );
edge->setVertex ( 1, pose );
edge->setMeasurement ( Eigen::Vector2d ( p.x, p.y ) );
edge->setParameterId ( 0,0 ); //cameraparameter
edge->setInformation ( Eigen::Matrix2d::Identity() );
optimizer.addEdge ( edge );
index++;
}
chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
optimizer.setVerbose ( true );
optimizer.initializeOptimization();
optimizer.optimize ( 100 );
chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>> ( t2-t1 );
cout<<"optimization costs time: "<<time_used.count() <<" seconds."<<endl;
cout<<endl<<"after optimization:"<<endl;
cout<<"T="<<endl<<Eigen::Isometry3d ( pose->estimate() ).matrix() <<endl;
}
I have defined a function to perform bundle adjustment with g2o, but terminal asserted Segmentation Fault when I ran the executable. I am sure that problem comes from this function because the whole program can run properly after commenting out this function.
My platform is Ubuntu16.04 LTS.
EDIT1: I tried to add set( CMAKE_BUILD_TYPE "Release" ) in my CMakeLists.txt. Then terminal asserted double free or corruption (out) after running the executable. However, it ran properly after I commenting out following code block:
g2o::CameraParameters* camera = new g2o::CameraParameters (K.at<double> ( 0,0 ), Eigen::Vector2d ( K.at<double> ( 0,2 ), K.at<double> ( 1,2 ) ), 0);
camera->setId ( 0 );
optimizer.addParameter ( camera );
EDIT2: The whole program could run properly once I employed default constructor of CameraParameter:
g2o::CameraParameters* camera = new g2o::CameraParameters ();
camera->setId ( 0 );
optimizer.addParameter ( camera );
However, segmentation fault existed still.
EDIT3: No segmentation faults occur any more after commenting out following codes:
optimizer.addVertex ( pose );
optimizer.addVertex ( point );
optimizer.addEdge ( edge );
optimizer.addParameter ( camera )
I am developing a game bot and using opencv and I am trying to make it detect spikes.
The spikes look like this :
What I tried was using a FastFeatureDetector to highlight keypoints , the result was the following :
The spikes are horizontal and change colors.the operation is on a full 1920x1080 screen
So my thinking was to take one of the points and compare to all of the other points X's since I have no way of filtering the result and 6094 KeyPoints the operation took too long. (37136836 iterations).
Is there a way to filter FastFeatureDetector results or should I approach this in another way?
my code :
Point * findSpikes( Mat frame , int * num_spikes )
{
Point * ret = NULL;
int spikes_counter = 0;
Mat frame2;
cvtColor( frame , frame2 , CV_BGR2GRAY );
Ptr<FastFeatureDetector> myBlobDetector = FastFeatureDetector::create( );
vector<KeyPoint> myBlobs;
myBlobDetector->detect( frame2 , myBlobs );
HWND wnd = FindWindow( NULL , TEXT( "Andy" ) );
RECT andyRect;
GetWindowRect( wnd , &andyRect );
/*Mat blobimg;
drawKeypoints( frame2 , myBlobs , blobimg );*/
//imshow( "Blobs" , blobimg );
//waitKey( 1 );
printf( "Size of vectors : %d\n" , myBlobs.size( ) );
for ( vector<KeyPoint>::iterator blobIterator = myBlobs.begin( ); blobIterator != myBlobs.end( ); blobIterator++ )
{
#pragma region FilteringArea
//filtering keypoints
if ( blobIterator->pt.x > andyRect.right || blobIterator->pt.x < andyRect.left
|| blobIterator->pt.y > andyRect.bottom || blobIterator->pt.y < andyRect.top )
{
printf( "Filtered\n" );
continue;
}
#pragma endregion
for ( vector<KeyPoint>::iterator comparsion = myBlobs.begin( ); comparsion != myBlobs.end( ); comparsion++ )
{
//filtering keypoints
#pragma region FilteringRegion
if ( comparsion->pt.x > andyRect.right || comparsion->pt.x < andyRect.left
|| comparsion->pt.y > andyRect.bottom || comparsion->pt.y < andyRect.top )
{
printf( "Filtered\n" );
continue;
}
printf( "Processing\n" );
double diffX = abs( blobIterator->pt.x - comparsion->pt.x );
if ( diffX <= 5 )
{
spikes_counter++;
printf( "Spike added\n" );
ret = ( Point * ) realloc( ret , sizeof( Point ) * spikes_counter );
if ( !ret )
{
printf( "Memory error\n" );
ret = NULL;
}
ret[spikes_counter - 1].y = ( ( blobIterator->pt.y + comparsion->pt.y ) / 2 );
ret[spikes_counter - 1].x = blobIterator->pt.x;
break;
}
#pragma endregion
}
}
( *( num_spikes ) ) = spikes_counter;
return ret;//Modify later
}
I'm aware of the usage of realloc and printf in C++ I just don't like cout and new
Are the spikes actually different sizes and irregularly spaced in real life? In your image they are regularly spaced and identically sized and so once you know the coordinates of one point, you can calculate all of the rest by simply adding a fixed increment to the X coordinate.
If the spikes are irregularly spaced and potentially different heights, I'd suggest you might try :
Use Canny edge detector to find the boundary between the spikes and the background
For each X coord in this edge image, search a single column of the edge image using minMaxIdx to find the brightest point in that column
If the Y coordinate of that point is higher up the screen than the Y coordinate of the brightest point in the previous column then the previous column was a spike, save (X,Y) coords.
If a spike was found in step 3, keep skipping across columns until the brightest Y coordinate in a column is the same as in the previous column. Then repeat spike detection, otherwise keep searching for next spike
Considering the form of your spikes, I'd suggest template pattern mathcing. It seems keypoints are a rather indirect approach.
I have been having problems with a uneasy to track down segmentation fault lately. The strange thing is, it lets me access the array fine, but for some reason it doesn't allow me to free it without causing the fault. I tested everything to make sure it wasn't anything else, so I can say with 100% certainty that it only occurs at the free line. The confusing thing is that the crash is very selective. As in, it only occurs after I press the help button on the menu in my game, yet it has no problems otherwise. After accessing the help section, it still allows access though, which makes the error even more strange. I may have the wrong idea about segmentation faults, but I'm pretty sure they don't usually allow access even if it isn't a significant error. I know they usually haven't for me. I would post the code here, but my project is very large. I'll try to post the parts of importance.
Here is how I allocate the array :
static void zero_array( void * memory, int elements, size_t element_size )
{
memset( memory, 0, elements * element_size );
return;
}
/* ******************************************************** */
static void fill_array_with_ones( void * memory, int elements, size_t element_size )
{
memset( memory, 1, elements * element_size );
return;
}
/* ******************************************************** */
static void * create_array( int elements, size_t element_size, t_setter setter )
{
void * temp = NULL;
if ( !( temp = malloc( elements * element_size ) ) )
{
perror( "malloc" );
exit( 1 );
}
if ( setter )
setter( temp, elements, element_size );
return temp;
}
I have tested this many times without problems. I use it mainly for my menu API I use to make it easier to track button events in SDL on bitmap images.
My setup code for the problem area looks like this :
extern void setup_mdata( game_data * game, menu * tmenu, const char * menu_image_path, int max_buttons, bool default_handling, t_handle_var_mdata handle_mdata )
{
int width = 0;
int height = 0;
tmenu->max_buttons = max_buttons;
tmenu->allocation_size = sizeof( bool ) * game->game_menu.max_buttons;
tmenu->hover_over_button = ( bool * )create_array( max_buttons, sizeof( bool ), zero_array );
tmenu->is_clicked = ( bool * )create_array( max_buttons, sizeof( bool ), zero_array );
if ( !default_handling )
tmenu->is_enabled = ( bool * )create_array( max_buttons, sizeof( bool ), fill_array_with_ones );
tmenu->button_shape = ( SDL_Rect * )create_array( max_buttons, sizeof( SDL_Rect ), zero_array );
tmenu->menu_image = load_texture( game->renderer, ( char * )menu_image_path, true, 255, 0, 255 );
SDL_QueryTexture( game->game_menu.menu_image, NULL, NULL, &width, &height );
handle_mdata( game, tmenu, width, height );
return;
}
Yet again, I have tested this code many times and it hasn't ever failed on any other menu. Which makes the problem very strange to me.
Here is how I call this function for both the main and help menu for the title screen :
setup_mdata( game, &game->title_menu, "bitmaps//title_menu.bmp", 3, true, setup_title_menu );
setup_mdata( game, &game->title_help_menu, "bitmaps//title_help_menu.bmp", 3, true, setup_title_help_menu );
I don't think it matters, but if you're wondering, here is the code to actually setup the menus with additional data.
static void setup_title_menu( game_data * game, menu * tmenu, int width, int height )
{
int nbutton = 0;
tmenu->button_highlight = ( SDL_Texture ** )create_array( 1, sizeof( SDL_Texture * ), zero_array );
*tmenu->button_highlight = load_texture( game->renderer, ( char * )"bitmaps//button4_highlight.bmp", true, 255, 255, 255 );
for ( ; nbutton < tmenu->max_buttons; nbutton++ )
{
MB_SHAPE.h = TITLE_BUTTON_HEIGHT;
MB_SHAPE.w = TITLE_BUTTON_WIDTH;
MB_SHAPE.x = menu_shape.x + FIRST_TITLE_BUTTON_X;
MB_SHAPE.y = menu_shape.y + FIRST_TITLE_BUTTON_Y + ( ( TITLE_BUTTON_HEIGHT + TITLE_BUTTON_DIVIDER_HEIGHT ) * nbutton );
}
return;
}
/* ******************************************************** */
static void setup_title_help_page_shape( game_data * game )
{
game->title_screen_data.help_page_shape.h = HELP_PAGE_HEIGHT;
game->title_screen_data.help_page_shape.w = HELP_PAGE_WIDTH;
game->title_screen_data.help_page_shape.x = menu_shape.x + 59;
game->title_screen_data.help_page_shape.y = menu_shape.y + 192;
return;
}
/* ******************************************************** */
static void setup_title_help_menu( game_data * game, menu * tmenu, int width, int height )
{
int nbutton = 0;
tmenu->button_highlight = ( SDL_Texture ** )create_array( 2, sizeof( SDL_Texture * ), zero_array );
tmenu->button_highlight[0] = load_texture( game->renderer, ( char * )"bitmaps//button2_highlight.bmp", true, 255, 255, 255 );
tmenu->button_highlight[1] = load_texture( game->renderer, ( char * )"bitmaps//triangle_highlight.bmp", true, 255, 255, 255 );
setup_title_help_page_shape( game );
for ( ; nbutton < tmenu->max_buttons; nbutton++ )
{
switch ( nbutton )
{
case GO_BACK :
tmenu->button_shape[GO_BACK].h = 50;
tmenu->button_shape[GO_BACK].w = 120;
tmenu->button_shape[GO_BACK].x = menu_shape.x + 329;
tmenu->button_shape[GO_BACK].y = menu_shape.y + 61;
break;
case ARROW_RIGHT :
tmenu->button_shape[ARROW_RIGHT].h = 34;
tmenu->button_shape[ARROW_RIGHT].w = 17;
tmenu->button_shape[ARROW_RIGHT].x = menu_shape.x + 432;
tmenu->button_shape[ARROW_RIGHT].y = menu_shape.y + 473;
break;
case ARROW_LEFT :
tmenu->button_shape[ARROW_LEFT].h = 34;
tmenu->button_shape[ARROW_LEFT].w = 17;
tmenu->button_shape[ARROW_LEFT].x = menu_shape.x + 390;
tmenu->button_shape[ARROW_LEFT].y = menu_shape.y + 473;
break;
}
}
return;
}
The part where it actually breaks is when I try to do this :
free( game->title_help_menu.is_clicked );
free( game->title_help_menu.hover_over_button );
If you're wondering, it doesn't break on the help menu arrays, for whatever reason. Which confuses me even more. I made sure it wasn't anything else by removing these functions, and it didn't throw a SIGSEGV. I figure there is some subtle problem that is causing this, but I have no idea what it is. I'm glad if any of you know more about debugging than I do and can at least make some suggestions on this.
The strange thing is, it lets me access the array fine, but for some reason it doesn't allow me to free it without causing the fault.
That isn't strange at all.
Most UNIX malloc implementations do not release freed memory to the OS immediately. Instead, they keep it on free-list, in the hope that application will ask for it again, and it will be readily available without executing system calls (which are expensive).
The confusing thing is that the crash is very selective.
That is also very typical for heap corruption problems. When you corrupt heap (e.g. by overflowing an allocated buffer, or freeing something twice), the crash may come much later, and may go away when you change something unrelated.
Good news: tools like Valgrind and Address Sanitizer usually help you find heap corruption problems very quickly and efficiently.
I am manually creating a set of QLabels that are being put into a QGridLayout, and should be distributed evenly. When I create a test form using the QT Designer and add a series of labels, and put them in a QGridLayout, the labels occupy the full size of their cells in the grid. When I do this manually in c++, the labels don't expand and say the minimum size for the text. I am able to get these labels to expand vertically, but not horizontally.
Here is how I'm creating the QGridLayout:
m_layout = new QGridLayout;
m_layout->setHorizontalSpacing( 1 );
m_layout->setVerticalSpacing( 1 );
m_layout->setContentsMargins(0,0,0,0);
m_layout->setMargin(0);
m_layout->setSizeConstraint( QGridLayout::SetDefaultConstraint );
//m_layout->setSizeConstraint( QGridLayout::SetMaximumSize );
When I change the size constraint, it does not affect the size of the labels at all, so then I assumed that the issue may lie on how I'm creating the labels, which happens like this:
QLabel *label = new QLabel;
label->setAlignment( Qt::AlignCenter );
label->setFrameStyle( QFrame::Raised );
label->setMinimumSize( QSize(0,0) );
label->setMaximumSize( QSize(16777215, 16777215) );
label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
Right now, all the QLabels are the same size, but eventually they will have differing sizes, which is why I'm using a packed-bin algorithm. I designed the algorithm around classes like this:
struct ButtonFittingNode
{
ButtonFittingNode( QRect rectangle, QGridLayout *layout )
: used( false )
, node( rectangle )
, down( NULL )
, right( NULL )
, m_layout( layout )
{ }
~ButtonFittingNode()
{
if ( down ) delete down;
if ( right ) delete right;
}
ButtonFittingNode *findNode( QLabel *btn )
{
int w = 1;
int h = 1;
if ( this->used )
{
ButtonFittingNode *bfn = NULL;
if ( this->right ) bfn = this->right->findNode( btn );
if ( this->down && !bfn ) bfn = this->down->findNode( btn );
return bfn;
}
else if ( ( w <= node.width() ) && ( h <= node.height() ) )
{
qDebug() << "Placing at " << node.x() << node.y();
m_layout->addWidget( btn, node.y(), node.x(), w, h, Qt::AlignJustify );
this->used = true;
this->splitNode( QSize( w, h ) );
return this;
}
return NULL;
}
void splitNode( QSize sz )
{
int w = 0, h = 0;
// Create a down node
w = this->node.width();
h = this->node.height() - sz.height();
if ( h > 0 )
{
QRect n( this->node.x(), this->node.y() + sz.height(), w, h );
this->down = new ButtonFittingNode( n, m_layout );
}
// Create a right node
w = this->node.size().width() - sz.width();
h = sz.height();
if ( w > 0 )
{
QRect n( this->node.x() + sz.width(), this->node.y(), w, h );
this->right = new ButtonFittingNode( n, m_layout );
}
}
bool used;
QRect node;
ButtonFittingNode *down;
ButtonFittingNode *right;
private:
QGridLayout *m_layout;
};
Using a 3x2 grid, I get the following output:
Sorry, I had to blur the text, since this is a work related project, but grey is background, white is the label's background. As you can see, they are tall, but skinny. I want these labels to be tall and fat. Am I setting some of the attributes wrong?
This is all really simple. The size constraint of the layout has got nothing to do with what you're seeing. You're also including a bunch of useless boilerplate code. Get rid of explicit setting of minimum and maximum sizes unless you have some non-default sizes in mind. This is completely useless:
label->setMinimumSize( QSize(0,0) );
label->setMaximumSize( QSize(16777215, 16777215) );
You need to set the label's sizePolicy to Expanding in the horizontal direction. That's all there's to it:
label->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
I see what you want from your bin packing system, but it won't work very well as-is, since the column/row sizes in the grid will vary as the grid gets resized. Your packer will choose some column/row spans based on then current row/column sizes. Upon resizing, the packer's decisions won't be adequate anymore.
What you really want is a custom layout that does all the packing on the fly. The flow layout example may be very close to what you want.
I´ve got problems with opening textures in SDL. I´ve got a function to read bmp files, optimize them and add colorkey:
SDL_Surface* SDLStuff::LoadImage( char* FileName ) {
printf( "Loading texture: \"%s\"\n", FileName );
SDL_Surface* loadedImage = 0;
SDL_Surface* optimizedImage = 0;
loadedImage = SDL_LoadBMP( FileName );
optimizedImage = SDL_DisplayFormat( loadedImage );
SDL_FreeSurface( loadedImage );
Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 255, 0, 255 );
SDL_SetColorKey( optimizedImage, SDL_RLEACCEL | SDL_SRCCOLORKEY, colorkey );
//SDL_SetColorKey(Tiles[0].Texture, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(Tiles[0].Texture->format, 255, 0 ,255));
Cache.push_back( optimizedImage );
return optimizedImage;
}
Which works great. I then load all my textures like this and this also works:
Objects[0].Texture = SDLS.LoadImage( "data/mods/default/sprites/house.bmp" );
Objects[1].Texture = SDLS.LoadImage( "data/mods/default/sprites/wall0.bmp" );
Objects[2].Texture = SDLS.LoadImage( "data/mods/default/sprites/wall1.bmp" );
Selector.Texture = SDLS.LoadImage( "data/mods/default/selector.bmp" );
Tiles[0].Texture = SDLS.LoadImage( "data/mods/default/tiles/grass.bmp" );
Tiles[1].Texture = SDLS.LoadImage( "data/mods/default/tiles/dirt.bmp" );
Tiles[2].Texture = SDLS.LoadImage( "data/mods/default/tiles/black.bmp" );
But I want to be able to control this stuff through some kind of data files. So I wrote a functionton parse a csv file. Then I get the values and try to read the bmp-files, like this:
void DataFile( std::string Mod, std::string FileName, std::string Separator = "\t" ) {
ini dataf;
dataf.Init();
dataf.LoadFile( "data/mods/" + Mod + "/" + FileName );
std::vector< std::vector< std::string > > MData = dataf.LoopCSV( Separator );
for ( unsigned int Row = 0; Row < MData.size(); Row++ ) {
if ( MData.at( Row ).size() > 0 ) {
if ( MData.at( Row )[0] == "TILE" ) {
if ( MData.at( Row ).size() == 4 ) {
std::string a = "data/mods/" + Mod + "/" + MData.at( Row )[3];
WriteLog( a.c_str() );
Tileset TTile;
TTile.WalkCost = String2Int( MData.at( Row )[2] );
TTile.Texture = SDLS.LoadImage( a.c_str() );
Tiles[String2Int(MData.at( Row )[1])] = TTile;
} else {
WriteLog( "Wrong number of arguments passed to TILE\n" );
}
}
}
}
dataf.Destroy();
}
This works perfectly well and it logs paths to files that actually exists, I´ve double checked every file. BUT the SDLS.LoadImage()-call fails anyway and the program crashes. If I comment out that line it all works perfect except that nothing is rendered where the tiles should be. But the files is there and works when I load them manually, and sdl is initialized before I try to call SDL_DisplayFormat(), so I don´t know what can be wrong with this :(
EDIT:
Just a note to not cunfuse people; the SDLStuff class uses a cache of the pointers to the textures. That way I can loop through the cache, being able to free all loaded textures with a single function call to a function in SDLStuff.
You may want to use SDL_image official library to load jpg, png, tiff etc:
http://www.libsdl.org/projects/SDL_image/
May be the better solution is to create an archive file with your resources and iterate files in it.
Benefits:
1. you do not need to create csv file.
2. your archived bmp will be of less size.
3. you can set a password for achive file to protect your resources from users.
Additional links:
http://www.zlib.net/
What libraries should I use to manipulate archives from C++?