| 1198 | } |
| 1199 | |
| 1200 | Mat overlay(const Mat& src, Mat& dst, const Point& origin, int alpha) |
| 1201 | { |
| 1202 | assert(src.channels() == 4 && dst.channels() == 4); // use alpha channel to blend |
| 1203 | assert(0 <= alpha && alpha < 256); |
| 1204 | |
| 1205 | Size size(src.cols, src.rows); |
| 1206 | Rect rect1(origin, size); |
| 1207 | Rect rect2(0, 0, dst.cols, dst.rows); |
| 1208 | |
| 1209 | // http://docs.opencv.org/2.4/modules/core/doc/basic_structures.html?highlight=rect#Rect_ |
| 1210 | rect1 &= rect2; |
| 1211 | if(rect1.area() <= 0) // not overlap |
| 1212 | return dst; |
| 1213 | |
| 1214 | // https://en.wikipedia.org/wiki/Alpha_compositing |
| 1215 | // if dst is BGR format, treat A as 255, namely opaque. |
| 1216 | Mat roi = dst(rect1); |
| 1217 | for(int r = 0; r < roi.rows; ++r) |
| 1218 | for(int c = 0; c < roi.cols; ++c) |
| 1219 | { |
| 1220 | const cv::Vec4b& src_bgra = src.at<cv::Vec4b>(r, c); |
| 1221 | cv::Vec4b& dst_bgra = roi.at<cv::Vec4b>(r, c); |
| 1222 | // cv::Vec3b& dst_bgr = dst_has_alpha? *reinterpret_cast<cv::Vec3b*>(&roi.at<cv::Vec4b>(r, c)) : roi.at<cv::Vec3b>(r, c); |
| 1223 | |
| 1224 | // cv::Vec3i src_bgr(src_bgra[0], src_bgra[1], src_bgra[2]); |
| 1225 | |
| 1226 | const uchar& src_a = src_bgra[3]; |
| 1227 | |
| 1228 | //(src_bgr * src_a + dst_bgr * 255 * (1 - src_a)) / (src_a + 255 * (1 - src_a)); |
| 1229 | //dst_color = dst_color * 255 + |
| 1230 | // https://docs.gimp.org/en/gimp-concepts-layer-modes.html |
| 1231 | // overlay |
| 1232 | if(src_a == 0) |
| 1233 | continue; |
| 1234 | |
| 1235 | float t = static_cast<float>(alpha * src_a)/(255 * 255); |
| 1236 | float one_minuse_t = 1.0f - t; |
| 1237 | |
| 1238 | dst_bgra[0] = cvRound((one_minuse_t * dst_bgra[0] + t * src_bgra[0])); |
| 1239 | dst_bgra[1] = cvRound((one_minuse_t * dst_bgra[1] + t * src_bgra[1])); |
| 1240 | dst_bgra[2] = cvRound((one_minuse_t * dst_bgra[2] + t * src_bgra[2])); |
| 1241 | // for(int i = 0; i < 3; ++i) |
| 1242 | // { |
| 1243 | // int value = cvRound((1.0f - t) * dst_bgra[i] + t * src_bgra[i]); |
| 1244 | |
| 1245 | // float value = dst_bgra[i]/255.0f * (dst_bgra[i] + 2* src_bgra[i]/255.0f*(255.0f - dst_bgra[i])); |
| 1246 | // assert(0 <= value && value <= 255.0f); |
| 1247 | // dst_bgr[i] = static_cast<uchar>(value); |
| 1248 | // int value = ((255 - src_a) * dst_bgra[i] + src_a * src_bgra[i]) / 255; |
| 1249 | // float value = (1.0f - alpha) * dst_bgra[i] + alpha * src_bgra[i]; |
| 1250 | // assert(0 <= value && value <= 255); |
| 1251 | // dst_bgra[i] = static_cast<uchar>(value); |
| 1252 | // } |
| 1253 | |
| 1254 | } |
| 1255 | |
| 1256 | return dst; |
| 1257 | } |
no outgoing calls
no test coverage detected