/// <summary> /// draw overlay(has transparent background ) on bg /// </summary> /// <param name="bg"></param> /// <param name="overlay"></param> public unsafe static void DrawOverlay(Mat bg, Mat overlay) { if (bg.Size() != overlay.Size()) { throw new System.ArgumentException("bg.Size()!=overlay.Size()"); } if (overlay.Channels() < 4) { throw new System.ArgumentException("overlay.Channels()<4"); } int colsOverlay = overlay.Cols; int rowsOverlay = overlay.Rows; //https://stackoverflow.com/questions/54069766/overlaying-an-image-over-another-image-both-with-transparent-background-using-op for (int i = 0; i < rowsOverlay; i++) { Vec3b *pBg = (Vec3b *)bg.Ptr(i); Vec4b *pOverlay = (Vec4b *)overlay.Ptr(i); for (int j = 0; j < colsOverlay; j++) { Vec3b *pointBg = pBg + j; Vec4b *pointOverlay = pOverlay + j; if (pointOverlay->Item3 != 0) { pointBg->Item0 = pointOverlay->Item0; pointBg->Item1 = pointOverlay->Item1; pointBg->Item2 = pointOverlay->Item2; } } } }
OpenCvSharp.Mat Draw( DrawingData data, Database database) { // drawing params of stripe with current faces int stripe_width = thumbnail_size * 2 + draw_border * 2; int stripe_height = (thumbnail_size + draw_border) * max_count_in_stripe - draw_border; // image for draw the frame and the stripe OpenCvSharp.Mat result = new OpenCvSharp.Mat( Math.Max(data.frame.Rows + data.depth.Rows, stripe_height), Math.Max(data.frame.Cols, data.depth.Cols) + stripe_width, OpenCvSharp.MatType.CV_8UC3, OpenCvSharp.Scalar.All(0)); // copy the frame int frame_y_offset = (result.Rows - data.frame.Rows - data.depth.Rows) / 2; int depth_y_offset = frame_y_offset + data.frame.Rows; data.frame.CopyTo( result[ new OpenCvSharp.Rect( 0, frame_y_offset, data.frame.Cols, data.frame.Rows)]); for (int i = 0; i < data.depth.Rows; ++i) { unsafe { UInt16 *src_ptr = (UInt16 *)data.depth.Ptr(i); byte * dst_ptr = (byte *)result.Ptr(depth_y_offset + i); for (int j = 0; j < data.depth.Cols; ++j, ++src_ptr, dst_ptr += 3) { UInt16 depth = *src_ptr; byte * bgr = dst_ptr; bgr[0] = bgr[1] = bgr[2] = 0; if (depth == 0) { continue; } if (depth < 256) { bgr[2] = (byte)(256 - depth); } if (depth < 256 * 2) { bgr[1] = (byte)(depth / 2); } else { bgr[1] = (byte)(255); } if (depth < 256 * 4) { bgr[0] = (byte)(depth / 4); } else { bgr[0] = (byte)(255); } } } } // clone faces data for random access List <Tuple <int, FaceData> > faces = new List <Tuple <int, FaceData> >(); foreach (KeyValuePair <int, FaceData> pair in data.faces) { faces.Add(new Tuple <int, FaceData>(pair.Key, pair.Value)); } // make order with recognized first // pair<match_database_index, index in faces> List <Tuple <int, int> > order = new List <Tuple <int, int> >(); for (int i = 0; i < faces.Count; ++i) { order.Add(new Tuple <int, int>(faces[i].Item2.match_database_index, i)); } order.Sort(); // draw alive faces for (int order_i = 0; order_i < order.Count; ++order_i) { FaceData face = faces[order[order_i].Item2].Item2; // draw circles of faces appeared on this frame if (face.frame_id == data.frame_id && !face.lost) { // get points List <Point> points = face.sample.getLandmarks(); // compute center OpenCvSharp.Point2f center = new OpenCvSharp.Point2f(0, 0); for (int j = 0; j < points.Count; ++j) { center.X += points[j].x; center.Y += points[j].y; } center *= 1.0 / points.Count; // compute radius double radius = 0; for (int j = 0; j < points.Count; ++j) { radius += OpenCvSharp.Point2f.Distance(new OpenCvSharp.Point2f(points[j].x, points[j].y), center); } radius *= 1.5 / points.Count; radius *= 2; // choose color OpenCvSharp.Scalar color = face.match_database_index < 0 ? new OpenCvSharp.Scalar(0, 0, 255) : // red color for unrecognized new OpenCvSharp.Scalar(0, 255, 0); // green color for recognizerd for (int k = 0; k < (data.depth.Empty() ? 1 : 2); ++k) { int y_offset = (k == 0 ? frame_y_offset : depth_y_offset); // dashed circle for weak face samples if (face.weak) { // draw dashed cirle for weak samples int n = 8; for (int i = 0; i < n; ++i) { OpenCvSharp.Cv2.Ellipse( result, (OpenCvSharp.Point)(center + new OpenCvSharp.Point2f(0f, y_offset)), new OpenCvSharp.Size(radius, radius), (face.frame_id * 2) % 360, (i * 2 + 0) * 180 / n, (i * 2 + 1) * 180 / n, color, 3, OpenCvSharp.LineTypes.AntiAlias); } } else { OpenCvSharp.Cv2.Circle( result, (OpenCvSharp.Point)(center + new OpenCvSharp.Point2f(0f, y_offset)), (int)radius, color, 3, OpenCvSharp.LineTypes.AntiAlias); } } } // no - draw the stripe if (order_i < max_count_in_stripe) { // place for thumbnail from the frame OpenCvSharp.Rect sample_rect = new OpenCvSharp.Rect( data.frame.Cols + draw_border, (thumbnail_size + draw_border) * order_i, thumbnail_size, thumbnail_size); // place for thumbnail from the database OpenCvSharp.Rect match_rect = new OpenCvSharp.Rect( data.frame.Cols + draw_border * 2 + thumbnail_size, (thumbnail_size + draw_border) * order_i, thumbnail_size, thumbnail_size); // make thumbnail from the frame Database.makeThumbnail(face.sample).CopyTo(result[sample_rect]); // fade if image is lost if (face.draw_multilier < 1) { result[sample_rect] *= face.draw_multilier; } if (face.match_database_index < 0) { // gray color for unrecognized persons result[match_rect].SetTo(128 * face.draw_multilier); } else { // thumbnail from the database for recognized persons database.thumbnails[face.match_database_index].CopyTo(result[match_rect]); // fade if image is lost if (face.draw_multilier < 1) { result[match_rect] *= face.draw_multilier; } } } } return(result); }
OpenCvSharp.Mat Draw( DrawingData data, Database database) { // drawing params of stripe with current faces int stripe_width = thumbnail_size * 2 + draw_border * 2; int stripe_height = (thumbnail_size + draw_border) * max_count_in_stripe - draw_border; // image for draw the frame and the stripe OpenCvSharp.Mat result = new OpenCvSharp.Mat( Math.Max(data.frame.Rows + data.depth.Rows, stripe_height), Math.Max(data.frame.Cols, data.depth.Cols) + stripe_width, OpenCvSharp.MatType.CV_8UC3, OpenCvSharp.Scalar.All(0)); // copy the frame int frame_y_offset = (result.Rows - data.frame.Rows - data.depth.Rows) / 2; int depth_y_offset = frame_y_offset + data.frame.Rows; data.frame.CopyTo( result[ new OpenCvSharp.Rect( 0, frame_y_offset, data.frame.Cols, data.frame.Rows)]); for (int i = 0; i < data.depth.Rows; ++i) { unsafe { UInt16 *src_ptr = (UInt16 *)data.depth.Ptr(i); byte * dst_ptr = (byte *)result.Ptr(depth_y_offset + i); for (int j = 0; j < data.depth.Cols; ++j, ++src_ptr, dst_ptr += 3) { UInt16 depth = *src_ptr; byte * bgr = dst_ptr; bgr[0] = bgr[1] = bgr[2] = 0; if (depth == 0) { continue; } if (depth < 256) { bgr[2] = (byte)(256 - depth); } if (depth < 256 * 2) { bgr[1] = (byte)(depth / 2); } else { bgr[1] = (byte)(255); } if (depth < 256 * 4) { bgr[0] = (byte)(depth / 4); } else { bgr[0] = (byte)(255); } } } } // clone faces data for random access List <Tuple <int, FaceData> > faces = new List <Tuple <int, FaceData> >(); foreach (KeyValuePair <int, FaceData> pair in data.faces) { faces.Add(new Tuple <int, FaceData>(pair.Key, pair.Value)); } // make order with recognized first // pair<match_database_index, index in faces> List <Tuple <int, int> > order = new List <Tuple <int, int> >(); for (int i = 0; i < faces.Count; ++i) { order.Add(new Tuple <int, int>(faces[i].Item2.match_database_index, i)); } order.Sort(); // draw alive faces for (int order_i = 0; order_i < order.Count; ++order_i) { FaceData face = faces[order[order_i].Item2].Item2; // draw circles of faces appeared on this frame if (face.frame_id == data.frame_id && !face.lost) { // get points List <Point> points = face.sample.getLandmarks(); List <Point> iris_points = face.sample.getIrisLandmarks(); // compute center OpenCvSharp.Point2f center = new OpenCvSharp.Point2f(0, 0); for (int j = 0; j < points.Count; ++j) { center.X += points[j].x; center.Y += points[j].y; } center *= 1.0 / points.Count; // compute radius double radius = 0; for (int j = 0; j < points.Count; ++j) { radius += OpenCvSharp.Point2f.Distance(new OpenCvSharp.Point2f(points[j].x, points[j].y), center); } radius *= 1.5 / points.Count; radius *= 2; RawSample.Rectangle rectangle = face.sample.getRectangle(); // set a point to place information for this face OpenCvSharp.Point2f text_point = new OpenCvSharp.Point2f( rectangle.x + rectangle.width + 3, rectangle.y + 10); const float text_line_height = 22; // choose color OpenCvSharp.Scalar color = face.match_database_index < 0 ? new OpenCvSharp.Scalar(0, 0, 255) : // red color for unrecognized new OpenCvSharp.Scalar(0, 255, 0); // green color for recognizerd for (int k = 0; k < (data.depth.Empty() ? 1 : 2); ++k) { int y_offset = (k == 0 ? frame_y_offset : depth_y_offset); // dashed circle for weak face samples if (face.weak) { // draw dashed cirle for weak samples int n = 8; for (int i = 0; i < n; ++i) { OpenCvSharp.Cv2.Ellipse( result, (OpenCvSharp.Point)(center + new OpenCvSharp.Point2f(0f, y_offset)), new OpenCvSharp.Size(radius, radius), (face.frame_id * 2) % 360, (i * 2 + 0) * 180 / n, (i * 2 + 1) * 180 / n, color, 3, OpenCvSharp.LineTypes.AntiAlias); } } else { OpenCvSharp.Cv2.Circle( result, (OpenCvSharp.Point)(center + new OpenCvSharp.Point2f(0f, y_offset)), (int)radius, color, 3, OpenCvSharp.LineTypes.AntiAlias); } } if (face.age_gender_set) { // draw AgeGenderEstimator.AgeGender age_gender = face.age_gender; string age_text = "age: "; switch (age_gender.age) { case AgeGenderEstimator.Age.AGE_KID: age_text += "kid "; break; case AgeGenderEstimator.Age.AGE_YOUNG: age_text += "young "; break; case AgeGenderEstimator.Age.AGE_ADULT: age_text += "adult "; break; case AgeGenderEstimator.Age.AGE_SENIOR: age_text += "senior "; break; } age_text += string.Format("years: {0:G3}", age_gender.age_years); puttext( result, age_text, text_point); text_point.Y += text_line_height; puttext( result, age_gender.gender == AgeGenderEstimator.Gender.GENDER_FEMALE ? "gender: female" : age_gender.gender == AgeGenderEstimator.Gender.GENDER_MALE ? "gender: male" : "?", text_point); text_point.Y += text_line_height; text_point.Y += text_line_height / 3; // Console.WriteLine(face.age_gender.age_years); } if (face.emotion_set) { // draw List <EmotionsEstimator.EmotionConfidence> emotions = face.emotion_confidence; for (int j = 0; j < emotions.Count; ++j) { EmotionsEstimator.Emotion emotion = emotions[j].emotion; float confidence = emotions[j].confidence; OpenCvSharp.Cv2.Rectangle( result, new OpenCvSharp.Rect( (int)text_point.X, (int)text_point.Y - (int)text_line_height / 2, (int)(100 * confidence), (int)text_line_height), emotion == EmotionsEstimator.Emotion.EMOTION_NEUTRAL ? new OpenCvSharp.Scalar(255, 0, 0) : emotion == EmotionsEstimator.Emotion.EMOTION_HAPPY ? new OpenCvSharp.Scalar(0, 255, 0) : emotion == EmotionsEstimator.Emotion.EMOTION_ANGRY ? new OpenCvSharp.Scalar(0, 0, 255) : emotion == EmotionsEstimator.Emotion.EMOTION_SURPRISE ? new OpenCvSharp.Scalar(0, 255, 255) : new OpenCvSharp.Scalar(0, 0, 0), -1); puttext( result, emotion == EmotionsEstimator.Emotion.EMOTION_NEUTRAL ? "neutral" : emotion == EmotionsEstimator.Emotion.EMOTION_HAPPY ? "happy" : emotion == EmotionsEstimator.Emotion.EMOTION_ANGRY ? "angry" : emotion == EmotionsEstimator.Emotion.EMOTION_SURPRISE ? "surprise" : "?", text_point + new OpenCvSharp.Point2f(100, 0)); text_point.Y += text_line_height; text_point.Y += text_line_height / 3; } } if (face.active_liveness_status.verdict != ActiveLiveness.Liveness.NOT_COMPUTED) { string active_liveness = ""; if (face.active_liveness_status.verdict == ActiveLiveness.Liveness.WAITING_FACE_ALIGN) { active_liveness += face.active_liveness_status.verdict.ToString(); } else { active_liveness += face.active_liveness_status.check_type.ToString(); active_liveness += ": "; active_liveness += face.active_liveness_status.verdict.ToString(); active_liveness += " " + face.active_liveness_status.progress_level.ToString(); } puttext(result, active_liveness, text_point); text_point.Y += text_line_height; text_point.Y += text_line_height / 3; } // // draw iris points // for(int j = 0; j < iris_points.Count; ++j) // { // int ms = 1; // OpenCvSharp.Scalar icolor = new OpenCvSharp.Scalar(50, 255, 50); // int oi = j - 20 * Convert.ToInt32(j >= 20); // Point pt1 = iris_points[j]; // Point pt2 = iris_points[(oi < 19 ? j : j - 15) + 1]; // OpenCvSharp.Point2f cv_pt1 = new OpenCvSharp.Point2f(pt1.x, frame_y_offset + pt1.y); // OpenCvSharp.Point2f cv_pt2 = new OpenCvSharp.Point2f(pt2.x, frame_y_offset + pt2.y); // // if(oi < 5) // { // icolor = new OpenCvSharp.Scalar(0, 165, 255); // if(oi == 0) // { // double iradius = Math.Sqrt(Math.Pow(pt1.x - pt2.x, 2) + Math.Pow(pt1.y - pt2.y, 2)); // OpenCvSharp.Cv2.Circle( // result, // cv_pt1, // (int) iradius, // icolor, // ms, // OpenCvSharp.LineTypes.AntiAlias); // } // }else // { // OpenCvSharp.Cv2.Line( // result, // cv_pt1, // cv_pt2, // icolor, // ms, // OpenCvSharp.LineTypes.AntiAlias); // } // // OpenCvSharp.Cv2.Circle( // result, // cv_pt1, // ms, // color, // -1, // OpenCvSharp.LineTypes.AntiAlias); // } } // no - draw the stripe if (order_i < max_count_in_stripe) { // place for thumbnail from the frame OpenCvSharp.Rect sample_rect = new OpenCvSharp.Rect( data.frame.Cols + draw_border, (thumbnail_size + draw_border) * order_i, thumbnail_size, thumbnail_size); // place for thumbnail from the database OpenCvSharp.Rect match_rect = new OpenCvSharp.Rect( data.frame.Cols + draw_border * 2 + thumbnail_size, (thumbnail_size + draw_border) * order_i, thumbnail_size, thumbnail_size); // make thumbnail from the frame Database.makeThumbnail(face.sample).CopyTo(result[sample_rect]); // fade if image is lost if (face.draw_multilier < 1) { result[sample_rect] *= face.draw_multilier; } if (face.match_database_index < 0) { // gray color for unrecognized persons result[match_rect].SetTo(128 * face.draw_multilier); } else { // thumbnail from the database for recognized persons database.thumbnails[face.match_database_index].CopyTo(result[match_rect]); // fade if image is lost if (face.draw_multilier < 1) { result[match_rect] *= face.draw_multilier; } } } } return(result); }