Pixel stretched when zooming QImage a lot
-
Hello,
I am drawin a QImage with the following code without any trouble:QPainter lPainter( this ); QImage lImage = QImage( reinterpret_cast<const uchar *>( aImage.mImageData.data() ), aImage.mWidth, aImage.mHeigth, QImage::Format_Grayscale16 ); lPainter.setWorldTransform( mTransform ); lPainter.drawImage( QPoint( 0, 0 ), lImage.scaled( QSize( width(), height() ), Qt::IgnoreAspectRatio, Qt::FastTransformation ) );My problem, is when I zoom in by modifying mTransform with a big mZoomFactor:
mTransform = QTransform(); mTransform.scale( mZoomFactor, mZoomFactor );The image is not evenly zoomed, see capture:

The column in red is twice larger than other columns. It appears again in later columns (but it doesnt look similar)
Using
Qt::SmoothTransformationinstead ofQt::FastTransformationis better, but it makes the image slightly blurry.Is there another way to control the scaling?
Thanks
-
@Bonnie said in Pixel stretched when zooming QImage a lot:
Qt::KeepAspectRatio
Well, I want my image to take the entire widget. I dont mind if the pixel are a bit stretched, as long as they all have the same size
@Mwoua said in Pixel stretched when zooming QImage a lot:
Well, I want my image to take the entire widget. I dont mind if the pixel are a bit stretched, as long as they all have the same size
Qt has no such an option. You have to write this scaling method by yourself.
-
Hello,
I am drawin a QImage with the following code without any trouble:QPainter lPainter( this ); QImage lImage = QImage( reinterpret_cast<const uchar *>( aImage.mImageData.data() ), aImage.mWidth, aImage.mHeigth, QImage::Format_Grayscale16 ); lPainter.setWorldTransform( mTransform ); lPainter.drawImage( QPoint( 0, 0 ), lImage.scaled( QSize( width(), height() ), Qt::IgnoreAspectRatio, Qt::FastTransformation ) );My problem, is when I zoom in by modifying mTransform with a big mZoomFactor:
mTransform = QTransform(); mTransform.scale( mZoomFactor, mZoomFactor );The image is not evenly zoomed, see capture:

The column in red is twice larger than other columns. It appears again in later columns (but it doesnt look similar)
Using
Qt::SmoothTransformationinstead ofQt::FastTransformationis better, but it makes the image slightly blurry.Is there another way to control the scaling?
Thanks
@Mwoua said in Pixel stretched when zooming QImage a lot:
Qt::FastTransformation
What do you expect? How should it be done otherwise?
-
@Mwoua said in Pixel stretched when zooming QImage a lot:
Qt::FastTransformation
What do you expect? How should it be done otherwise?
@Christian-Ehrlicher I expect all pixels to have the same size, Qt::SmoothTransformation does it, but it makes the image blurry.
So I was wondering if there is another alternative
-
@Christian-Ehrlicher I expect all pixels to have the same size, Qt::SmoothTransformation does it, but it makes the image blurry.
So I was wondering if there is another alternative
-
@SGaist I am using this line:
QImage lImage = QImage( reinterpret_cast<const uchar *>( aImage.mImageData.data() ), aImage.mWidth, aImage.mHeigth, QImage::Format_Grayscale16 );It's called during the paintevent and aImage goes out of scope at the end of the function
and aImage.mImageData is a std::vector<uint16_t>
-
@SGaist I am using this line:
QImage lImage = QImage( reinterpret_cast<const uchar *>( aImage.mImageData.data() ), aImage.mWidth, aImage.mHeigth, QImage::Format_Grayscale16 );It's called during the paintevent and aImage goes out of scope at the end of the function
and aImage.mImageData is a std::vector<uint16_t>
-
struct sImageData { std::vector<uint16_t> mImageData; uint32_t mWidth, mHeigth; bool mDrawn = false; };mImageData has a size of mWidth*mHeigth.
In the current state, I generate the input array (with mostly random values + a number printed on it) to simulate a sensor
So currently it looks like noise, but eventually it will be a somewhat real imageIf it's any help, here is the code that generate data currently:
constexpr unsigned int FRAME_COUNT = 16U; mVirtualData.reserve( FRAME_COUNT ); for( auto lFrame = 0U; lFrame < FRAME_COUNT; ++lFrame ) { sFrameData lFrameData{}; lFrameData.mFrameData.resize( mFrameWidth * mFrameHeight, 0 ); // Put random pixel data for( auto &lPixelData : lFrameData.mFrameData ) { constexpr uint16_t BASE_PIXEL_VALUE = 32000; constexpr auto RANDOM_RANGE = 10000; lPixelData = BASE_PIXEL_VALUE + ( std::rand() % ( RANDOM_RANGE * 2 ) ) - RANDOM_RANGE; } cv::Mat imgDisplay16( mFrameHeight, mFrameWidth, CV_16U, lFrameData.mFrameData.data() ); // Add the frame counter cv::Point text_position( 20, 70 ); cv::Scalar font_Color( 0, 0, 0 ); const int32_t font_size = 2; const int32_t font_weight = 3; const std::string lFrameText = std::to_string( lFrame ); cv::putText( imgDisplay16, lFrameText, text_position, 3, font_size, font_Color, font_weight ); // Add a cross in the middle const unsigned int lCrossSize = mFrameWidth / 20U; cv::Point ptXS( mFrameWidth / 2 - lCrossSize, mFrameHeight / 2 ); cv::Point ptXE( mFrameWidth / 2 + lCrossSize, mFrameHeight / 2 ); cv::Point ptYS( mFrameWidth / 2, mFrameHeight / 2 - lCrossSize ); cv::Point ptYE( mFrameWidth / 2, mFrameHeight / 2 + lCrossSize ); cv::line( imgDisplay16, ptXS, ptXE, font_Color, 1, cv::LINE_AA ); cv::line( imgDisplay16, ptYS, ptYE, font_Color, 1, cv::LINE_AA ); mVirtualData.push_back( std::move( lFrameData ) ); } -
@Christian-Ehrlicher I expect all pixels to have the same size, Qt::SmoothTransformation does it, but it makes the image blurry.
So I was wondering if there is another alternative
@Mwoua said in Pixel stretched when zooming QImage a lot:
expect all pixels to have the same size,
How should this work with FastTransformation?
-
@Mwoua said in Pixel stretched when zooming QImage a lot:
expect all pixels to have the same size,
How should this work with FastTransformation?
@Christian-Ehrlicher I dont really know what fasttransformation does. It says " The transformation is performed quickly, with no smoothing." So I dont know what is the expected result
I don't think I really need smoothing, it's probably just a rounding error or something like that. Hence why I am asking about alternatives
-
@Christian-Ehrlicher I dont really know what fasttransformation does. It says " The transformation is performed quickly, with no smoothing." So I dont know what is the expected result
I don't think I really need smoothing, it's probably just a rounding error or something like that. Hence why I am asking about alternatives
@Mwoua said in Pixel stretched when zooming QImage a lot:
So I dont know what is the expected result
Nothing expensive is done so the only way to do is, is to duplicate some rows / columns.
-
@Mwoua said in Pixel stretched when zooming QImage a lot:
So I dont know what is the expected result
Nothing expensive is done so the only way to do is, is to duplicate some rows / columns.
@Christian-Ehrlicher Ok, thanks for the info, thats good to know.
Is Qt::SmoothTransformation the only alternative?
-
@Christian-Ehrlicher Ok, thanks for the info, thats good to know.
Is Qt::SmoothTransformation the only alternative?
-
@Mwoua :
Is Qt::SmoothTransformation the only alternative?
For
transformMode, yes.
Aren't you expectingQt::FastTransformationwithQt::KeepAspectRatio? -
@Bonnie said in Pixel stretched when zooming QImage a lot:
Qt::KeepAspectRatio
Well, I want my image to take the entire widget. I dont mind if the pixel are a bit stretched, as long as they all have the same size
@Mwoua said in Pixel stretched when zooming QImage a lot:
Well, I want my image to take the entire widget. I dont mind if the pixel are a bit stretched, as long as they all have the same size
Qt has no such an option. You have to write this scaling method by yourself.
-
M Mwoua has marked this topic as solved on
-
@Bonnie said in Pixel stretched when zooming QImage a lot:
Qt::KeepAspectRatio
Well, I want my image to take the entire widget. I dont mind if the pixel are a bit stretched, as long as they all have the same size
@Mwoua Hey, I have an idea.
First use Qt::KeepAspectRatio + Qt::FastTransformation to scale to a ratio-fixed size, then scale it again with Qt::IgnoreAspectRatio + Qt::SmoothTransformation , something likeQSize targetSize ( width(), height() ); QImage targetImage = lImage.scaled(targetSize , Qt::KeepAspectRatio, Qt::FastTransformation ); if(targetImage.size() != targetSize ) targetImage = targetImage.scaled(targetSize , Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); -
@Mwoua Hey, I have an idea.
First use Qt::KeepAspectRatio + Qt::FastTransformation to scale to a ratio-fixed size, then scale it again with Qt::IgnoreAspectRatio + Qt::SmoothTransformation , something likeQSize targetSize ( width(), height() ); QImage targetImage = lImage.scaled(targetSize , Qt::KeepAspectRatio, Qt::FastTransformation ); if(targetImage.size() != targetSize ) targetImage = targetImage.scaled(targetSize , Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); -
If you double the image in size (i.e. twice the number of pixels in both width and height) it is quite easy to draw the zoomed image by doubling the pixels both in the x and y direction. However, if you don't have a perfect multiple there is no perfect solution available. With the approach that fast transformation uses only some pixels can be doubled. Smooth transformation instead interpolates the colors of neighboring pixels to get a new color. This will always make the image look a little bit blurry. I don't know of any other way than to either use the color of just a single pixel or interpolate the colors of neighboring pixels. Only AI could invent some new pixels to fill the gaps properly (with no guarantee of accuracy of the final image to be displayed). You cannot use information which is not there.
The best thing you could do is to scale the image only by multiples of the original size using the fast transformation. A slight variation could be that 50% and 25% of the image size is also easy to achieve. Those images (after first scaling them down) could also be scaled up to multiples of their size with proper pixel sizes. This would allow intermediate steps of 3/2 (3x 50%) or 5/4 (5x 25%). Though, first scaling them down looses some information, but might look good.
-
If you double the image in size (i.e. twice the number of pixels in both width and height) it is quite easy to draw the zoomed image by doubling the pixels both in the x and y direction. However, if you don't have a perfect multiple there is no perfect solution available. With the approach that fast transformation uses only some pixels can be doubled. Smooth transformation instead interpolates the colors of neighboring pixels to get a new color. This will always make the image look a little bit blurry. I don't know of any other way than to either use the color of just a single pixel or interpolate the colors of neighboring pixels. Only AI could invent some new pixels to fill the gaps properly (with no guarantee of accuracy of the final image to be displayed). You cannot use information which is not there.
The best thing you could do is to scale the image only by multiples of the original size using the fast transformation. A slight variation could be that 50% and 25% of the image size is also easy to achieve. Those images (after first scaling them down) could also be scaled up to multiples of their size with proper pixel sizes. This would allow intermediate steps of 3/2 (3x 50%) or 5/4 (5x 25%). Though, first scaling them down looses some information, but might look good.
@SimonSchroeder Yeah I went with a custom scaling method and using fast transformation.
When there are a lot of pixel drawn, I still have some doubled pixel (probably), but i cant notice it because its too small. However, when it is zoomed enough, it looks good.
My method is really simple, but it's fast enough. To keep it simple, I compute the area I want to see and copy these pixels to a new buffer I give to QImage. Then I let FastTransformation do its job