I'm currently working on 2D transformations (translation, scaling, shearing and rotation) in Qt. I have a problem with bilinear interpolation, which I want to use to cover the 'black pixels' in output image. I'm using matrix calculations to get new coordinates of pixels of input image. Then I use reverse matrix calculation to check which pixel of input image responds to output pixel. Result of that is some float number which I use to interpolation. I check the four neighbour points and calculate the value (color) of output pixel. I have checked my calculations 'by hand' and they seem to be good.

Can anyone find any bug in that code? (I cut out the parts of code which are responsible for interface such as sliders).

Here is what i get: http://imgur.com/a/vSYkF
Qt Code:
  1. Geometric::Geometric(QWidget* parent) : QWidget(parent) {
  2. resize(1000, 800);
  3. displayLogoDefault = true;
  4.  
  5. a = shx = shy = x0 = y0 = 0;
  6. scx = scy = 1;
  7. tx = ty = 0;
  8. x = 200, y = 200;
  9. paintT = paintSc = paintR = paintShx = paintShy = false;
  10.  
  11. img = new QImage(600,600,QImage::Format_RGB32);
  12. img2 = new QImage("logo.jpeg");
  13. }
  14. Geometric::~Geometric() {
  15. delete img;
  16. delete img2;
  17. img = NULL;
  18. img2 = NULL;
  19. }
  20.  
  21. void Geometric::makeChange() {
  22. displayLogoDefault = false;
  23.  
  24. // iteration through whole input image
  25. for(int i = 0; i < img2->width(); i++) {
  26. for(int j = 0; j < img2->height(); j++) {
  27.  
  28. // calculate new coordinates basing on given 2D transformations values
  29. //I calculated that formula eariler by multiplying/adding matrixes
  30. x = cos(a)*scx*(i-x0) - sin(a)*scy*(j-y0) + shx*sin(a)*scx*(i-x0) + shx*cos(a)*scy*(j-y0);
  31. y = shy*(x) + sin(a)*scx*(i-x0) + cos(a)*scy*(j-y0);
  32.  
  33. // tx and ty goes for translation. scx and scy for scaling
  34. // shx and shy for shearing and a is angle for rotation
  35.  
  36. x += (x0 + tx);
  37. y += (y0 + ty);
  38.  
  39. if(x >= 0 && y >= 0 && x < img->width() && y < img->height()) {
  40. // reverse matrix calculation formula to find proper pixel from input image
  41. float tmx = x - x0 - tx;
  42. float tmy = y - y0 - ty;
  43. float recX = 1/scx * ( cos(-a)*( (tmx + shx*shy*tmx - shx*tmx) ) + sin(-a)*( shy*tmx - tmy ) ) + x0 ;
  44. float recY = 1/scy * ( sin(-a)*(tmx + shx*shy*tmx - shx*tmx) - cos(-a)*(shy*tmx-tmy) ) + y0;
  45.  
  46.  
  47. // here the interpolation starts. I calculate the color basing on four points from input image
  48. // that points are taken from the reverse matrix calculation
  49. float a = recX - floorf(recX);
  50. float b = recY - floorf (recY);
  51.  
  52. if(recX + 1 > img2->width()) recX -= 1;
  53. if(recY + 1 > img2->height()) recY -= 1;
  54.  
  55. QColor c1 = QColor(img2->pixel(recX, recY));
  56. QColor c2 = QColor(img2->pixel(recX + 1, recY));
  57. QColor c3 = QColor(img2->pixel(recX , recY + 1));
  58. QColor c4 = QColor(img2->pixel(recX + 1, recY + 1));
  59.  
  60. float colR = b * ((1.0 - a) * (float)c3.red() + a * (float)c4.red()) + (1.0 - b) * ((1.0 - a) * (float)c1.red() + a * (float)c2.red());
  61. float colG = b * ((1.0 - a) * (float)c3.green() + a * (float)c4.green()) + (1.0 - b) * ((1.0 - a) * (float)c1.green() + a * (float)c2.green());
  62. float colB = b * ((1.0 - a) * (float)c3.blue() + a * (float)c4.blue()) + (1.0 - b) * ((1.0 - a) * (float)c1.blue() + a * (float)c2.blue());
  63. if(colR > 255) colR = 255; if(colG > 255) colG = 255; if(colB > 255) colB = 255;
  64. if(colR < 0 ) colR = 0; if(colG < 0 ) colG = 0; if(colB < 0 ) colB = 0;
  65. paintPixel(x, y, colR, colG, colB);
  66. }
  67. }
  68. }
  69. // x0 and y0 are the starting point of image
  70. x0 = abs(x-tx);
  71. y0 = abs(y-ty);
  72. repaint();
  73. }
  74.  
  75. // function painting a pixel. It works directly on memory
  76. void Geometric::paintPixel(int i, int j, int r, int g, int b) {
  77. unsigned char *ptr = img->bits();
  78. ptr[4 * (img->width() * j + i)] = b;
  79. ptr[4 * (img->width() * j + i) + 1] = g;
  80. ptr[4 * (img->width() * j + i) + 2] = r;
  81.  
  82. }
  83.  
  84. void Geometric::paintEvent(QPaintEvent*) {
  85. QPainter p(this);
  86. p.drawImage(0, 0, *img);
  87. if (displayLogoDefault == true) p.drawImage(0, 0, *img2);
  88. }
To copy to clipboard, switch view to plain text mode