天天看點

opencv 實作PNG的透明背景

  1. 轉自:http://www.opencv.org.cn/forum.php?mod=viewthread&tid=32871
  2. void overlayImage(const cv::Mat &background, const cv::Mat &foreground,
  3.   cv::Mat &output, cv::Point2i location)
  4. {
  5.   background.copyTo(output);
  6.   // start at the row indicated by location, or at row 0 if location.y is negative.
  7.   for(int y = std::max(location.y , 0); y < background.rows; ++y)
  8.   {
  9.     int fY = y - location.y; // because of the translation
  10.     // we are done of we have processed all rows of the foreground image.
  11.     if(fY >= foreground.rows)
  12.       break;
  13.     // start at the column indicated by location,
  14.     // or at column 0 if location.x is negative.
  15.     for(int x = std::max(location.x, 0); x < background.cols; ++x)
  16.     {
  17.       int fX = x - location.x; // because of the translation.
  18.       // we are done with this row if the column is outside of the foreground image.
  19.       if(fX >= foreground.cols)
  20.         break;
  21.       // determine the opacity of the foregrond pixel, using its fourth (alpha) channel.
  22.       double opacity =
  23.         ((double)foreground.data[fY * foreground.step + fX * foreground.channels() + 3])
  24.         / 255.;
  25.       // and now combine the background and foreground pixel, using the opacity,
  26.       // but only if opacity > 0.
  27.       for(int c = 0; opacity > 0 && c < output.channels(); ++c)
  28.       {
  29.         unsigned char foregroundPx =
  30.           foreground.data[fY * foreground.step + fX * foreground.channels() + c];
  31.         unsigned char backgroundPx =
  32.           background.data[y * background.step + x * background.channels() + c];
  33.         output.data[y*output.step + output.channels()*x + c] =
  34.           backgroundPx * (1.-opacity) + foregroundPx * opacity;
  35.       }
  36.     }
  37.   }
  38. }
  39. This code only works if:
  40.     The background is in BGR colour space.
  41.     The foreground is in BGRA colour space.
  42. The output image will always be of the same size as the background image, in BGR colour space. The position parameter determines how the foreground is placed on top of the background. A position of (100, -50) will move the foreground 100 pixels to the right and 50 pixels up.
  43. It might not be the best solution as it was written in a hurry, so please feel free to improve.
  44. Explanation of the code:
  45. We first copy the background to the output, so we can continue with only the pixels where foreground and background overlap.
  46. We start at the first scanline where they overlap, being either the top row of the background (y=0) or the top row of the foreground (y = position.y), so we take the maximum of these two. We do the same for the column value (x). We use fX and fY (foreground-x and foreground-y) as the current coordinates in the foreground image.
  47. We determine the opacity of the foreground image using its fourth (alpha) channel. If it is > 0, we combine the pixels of the background and foreground for all channels.
  48. We are done if we passed all overlapping pixels and output will now contain an image of the background, overlayed with the transparent foreground image.
  49. Example usage:
  50. int main(int argc, char *argv[])
  51. {
  52.   // add the second parameter "-1" as flag, to make sure the transparancy channel is read!
  53.   cv::Mat foreground = imread("D:/images/foreground.png", -1);
  54.   cv::Mat background = imread("D:/images/background.jpg");
  55.   cv::Mat result;
  56.   overlayImage(background, foreground, result, cv::Point(0,0));
  57.   cv::imshow("result", result);
  58. }