From 379c9650894921633f6a6c8cb5a14f12cef2f6e8 Mon Sep 17 00:00:00 2001
From: zhangzengfei <zhangzengfei@smartai.com>
Date: 星期日, 26 五月 2024 02:48:58 +0800
Subject: [PATCH] 入侵抓拍转人脸添加小图

---
 pkg/image.go             |  264 ++++++++++++++++++++++++++++++++++++++++++++
 controller/captureCtl.go |   62 +++++++++
 2 files changed, 323 insertions(+), 3 deletions(-)

diff --git a/controller/captureCtl.go b/controller/captureCtl.go
index 4ea6154..a6fc5cb 100644
--- a/controller/captureCtl.go
+++ b/controller/captureCtl.go
@@ -1,7 +1,9 @@
 package controller
 
 import (
+	"encoding/base64"
 	"gat1400Exchange/config"
+	"gat1400Exchange/pkg"
 	"gat1400Exchange/service"
 	"net/http"
 	"time"
@@ -62,6 +64,7 @@
 
 	c.JSON(http.StatusOK, gin.H{"ResponseStatusObject": rspMsg})
 }
+
 func (a CaptureController) VideoLabels(c *gin.Context) {
 	var req vo.RequestVideoLabelList
 	if err := c.BindJSON(&req); err != nil {
@@ -87,15 +90,68 @@
 	face.FaceAppearTime = videoLabel.BehaviorAnalysisObject.BehaviorBeginTime
 	face.FaceDisAppearTime = videoLabel.BehaviorAnalysisObject.BehaviorEndTime
 
-	for idx, _ := range videoLabel.SubImageList.SubImageInfoObject {
+	var hasTargetImage bool
+	var bgImageWith, bgImageHeight int
+	var bgImage *vo.SubImageInfoObject
+	for idx, img := range videoLabel.SubImageList.SubImageInfoObject {
 		videoLabel.SubImageList.SubImageInfoObject[idx].EventSort = 10
+
+		// 鍒ゆ柇鏄惁鏈夊皬鍥�, 濡傛灉娌℃湁鍒囦竴寮�
+		if img.Type == "14" {
+			bgImageWith, bgImageHeight = img.Width, img.Height
+		} else {
+			hasTargetImage = true
+			bgImage = &videoLabel.SubImageList.SubImageInfoObject[idx]
+		}
+
+		face.SubImageList.SubImageInfoObject = append(
+			face.SubImageList.SubImageInfoObject,
+			videoLabel.SubImageList.SubImageInfoObject[idx],
+		)
 	}
 
-	face.SubImageList.SubImageInfoObject = videoLabel.SubImageList.SubImageInfoObject
+	if !hasTargetImage && bgImage != nil {
+		imgData, err := base64.StdEncoding.DecodeString(bgImage.Data)
+		if err != nil {
+			c.AbortWithStatus(http.StatusBadRequest)
+			return
+		}
+
+		var subRect pkg.Rect
+		subRect.Left = bgImageWith / 3
+		subRect.Top = bgImageHeight / 3
+		subRect.Right = subRect.Left * 2
+		subRect.Bottom = subRect.Top * 2
+
+		subImage, err := pkg.SubCutImage(imgData, &subRect, 0)
+		if err != nil {
+			c.AbortWithStatus(http.StatusBadRequest)
+			return
+		}
+
+		var subImageInfo = vo.SubImageInfoObject{
+			ImageID:     bgImage.ImageID + "1",
+			EventSort:   10,
+			DeviceID:    bgImage.DeviceID,
+			StoragePath: "",
+			Type:        "11",
+			FileFormat:  "Jpeg",
+			ShotTime:    bgImage.ShotTime,
+			Width:       subRect.Right - subRect.Left,
+			Height:      subRect.Top - subRect.Bottom,
+			Data:        base64.StdEncoding.EncodeToString(subImage),
+		}
+		face.SubImageList.SubImageInfoObject = append(
+			face.SubImageList.SubImageInfoObject,
+			subImageInfo,
+		)
+	}
 
 	// 濡傛灉寮�鍚簡涓嬬骇, 韬唤搴旇鏄秷鎭唬鐞�, 涓嶅啀杞彂鍒版湇鍔″櫒
 	if config.ClientConf.Enable && config.ServeConf.Role == "agent" {
-		//go a.Repository.VIIDMsgForward(&req)
+		var faceObjList vo.RequestFaceList
+		faceObjList.FaceListObject.FaceObject = append(faceObjList.FaceListObject.FaceObject, face)
+		go a.Repository.VIIDMsgForward(&faceObjList)
 	} else if config.ServeConf.Role == "cascade" {
 		go service.AddFaceNotification(&face)
 	}
diff --git a/pkg/image.go b/pkg/image.go
new file mode 100644
index 0000000..b14ea21
--- /dev/null
+++ b/pkg/image.go
@@ -0,0 +1,264 @@
+package pkg
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/base64"
+	"image"
+	"image/color"
+	"image/jpeg"
+	"log"
+)
+
+type Image struct {
+	Data   []byte
+	Width  int
+	Height int
+}
+
+type Rect struct {
+	Left   int
+	Top    int
+	Right  int
+	Bottom int
+}
+
+func SubCutImage(srcImage []byte, rect *Rect, enlarge int) ([]byte, error) {
+	img, err := ReadImageData(srcImage)
+	if err != nil {
+		return nil, err
+	}
+
+	bkImg, _ := DataToImage(img.Data, img.Width, img.Height)
+
+	cutRect := image.Rect(rect.Left, rect.Top, rect.Right, rect.Bottom)
+
+	if enlarge > 0 {
+		enlargeRect := EnlargeCut(rect, img.Width, img.Height, enlarge)
+		squareRect := LetterBox(enlargeRect, img.Width, img.Height)
+		cutRect = image.Rect(squareRect.Left, squareRect.Top, squareRect.Right, squareRect.Bottom)
+	}
+
+	subImg := bkImg.(*image.RGBA).SubImage(cutRect)
+
+	dstImage, err := ImageToJpeg(subImg, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return dstImage, nil
+}
+
+func ReadImageData(srcImage []byte) (*Image, error) {
+	bt := bytes.NewBuffer(srcImage)
+	img, _, err := image.Decode(bt)
+	if err != nil {
+		return nil, err
+	}
+
+	bgr := Image2BGR(img)
+
+	return &Image{
+		Width:  img.Bounds().Dx(),
+		Height: img.Bounds().Dy(),
+		Data:   bgr,
+	}, nil
+}
+
+// letterbox 鎸夌収瀹借竟淇敼鐩爣妗嗕负姝f柟褰�
+func LetterBox(rect *Rect, maxW, maxH int) *Rect {
+	width := rect.Right - rect.Left
+	height := rect.Bottom - rect.Top
+
+	// 璁$畻鐩爣妗嗙殑涓績鐐瑰潗鏍�
+	centerX := (rect.Left + rect.Right) / 2
+	centerY := (rect.Top + rect.Bottom) / 2
+
+	// 濡傛灉瀹藉害澶т簬楂樺害锛屽垯浠ラ珮搴︿负鍩哄噯璋冩暣瀹藉害锛屼娇鍏舵垚涓烘鏂瑰舰
+	if width > height {
+		newWidth := height
+		newLeft := centerX - newWidth/2
+		newRight := centerX + newWidth/2
+
+		// 璋冩暣鍚庣殑姝f柟褰㈡瓒呭嚭鍥惧儚杈圭晫鏃剁殑澶勭悊
+		if newLeft < 0 {
+			// 濡傛灉宸﹁竟鐣岃秴鍑猴紝鍚戝彸绉诲姩鍙宠竟鐣�
+			newRight += -newLeft
+			newLeft = 0
+		}
+		if newRight > maxW {
+			// 濡傛灉鍙宠竟鐣岃秴鍑猴紝鍚戝乏绉诲姩宸﹁竟鐣�
+			newLeft -= newRight - maxW
+			newRight = maxW
+		}
+
+		return &Rect{
+			Left:   newLeft,
+			Top:    rect.Top,
+			Right:  newRight,
+			Bottom: rect.Bottom,
+		}
+	}
+
+	// 濡傛灉楂樺害澶т簬瀹藉害锛屽垯浠ュ搴︿负鍩哄噯璋冩暣楂樺害锛屼娇鍏舵垚涓烘鏂瑰舰
+	if height > width {
+		newHeight := width
+		newTop := centerY - newHeight/2
+		newBottom := centerY + newHeight/2
+
+		// 璋冩暣鍚庣殑姝f柟褰㈡瓒呭嚭鍥惧儚杈圭晫鏃剁殑澶勭悊
+		if newTop < 0 {
+			// 濡傛灉涓婅竟鐣岃秴鍑猴紝鍚戜笅绉诲姩涓嬭竟鐣�
+			newBottom += -newTop
+			newTop = 0
+		}
+		if newBottom > maxH {
+			// 濡傛灉涓嬭竟鐣岃秴鍑猴紝鍚戜笂绉诲姩涓婅竟鐣�
+			newTop -= newBottom - maxH
+			newBottom = maxH
+		}
+
+		return &Rect{
+			Left:   rect.Left,
+			Top:    newTop,
+			Right:  rect.Right,
+			Bottom: newBottom,
+		}
+	}
+
+	// 濡傛灉瀹藉害鍜岄珮搴︾浉绛夛紝鍒欏凡缁忔槸姝f柟褰紝鐩存帴杩斿洖鍘熷鐭╁舰
+	return rect
+}
+
+// 闀垮鍙樹负涓�姣斾竴锛屾瘡杈瑰悇鎵╃櫨鍒嗕箣...
+func EnlargeCut(rect *Rect, maxW, maxH int, enlargePer int) *Rect {
+	// 鍏堟妸闀垮鍙樹负涓�姣斾竴
+	x0 := rect.Left
+	y0 := rect.Top
+	x1 := rect.Right
+	y1 := rect.Bottom
+
+	chaZhi := (y1 - y0) - (x1 - x0)
+	if chaZhi > 0 {
+		x0 = x0 - chaZhi/2
+		if x0 < 0 {
+			x0 = 0
+		}
+		x1 = x1 + chaZhi/2
+		if x1 > maxW {
+			x1 = maxW
+		}
+	} else {
+		y0 = y0 + chaZhi/2
+		if y0 < 0 {
+			y0 = 0
+		}
+		y1 = y1 - chaZhi/2
+		if y1 > maxH {
+			y1 = maxH
+		}
+	}
+
+	// 鍐嶆妸姣忚竟鍚勬墿澶х櫨鍒嗕箣...
+	enlarge := float32(enlargePer) / 100
+	x0New := int((1+enlarge)*float32(x0) - enlarge*float32(x1))
+	if x0New < 0 {
+		x0New = 0
+	}
+
+	x1New := int((1+enlarge)*float32(x1) - enlarge*float32(x0))
+	if x1New > maxW {
+		x1New = maxW
+	}
+
+	y0New := int((1+enlarge)*float32(y0) - enlarge*float32(y1))
+	if y0New < 0 {
+		y0New = 0
+	}
+
+	y1New := int((1+enlarge)*float32(y1) - enlarge*float32(y0))
+	if y1New > maxH {
+		y1New = maxH
+	}
+
+	return &Rect{
+		Left:   x0New,
+		Top:    y0New,
+		Right:  x1New,
+		Bottom: y1New,
+	}
+}
+
+func DataToImage(data []byte, w, h int) (image.Image, error) {
+	width := w
+	height := h
+	step := w * 3
+	channels := 3
+
+	img := image.NewRGBA(image.Rect(0, 0, width, height))
+	c := color.RGBA{
+		R: uint8(0),
+		G: uint8(0),
+		B: uint8(0),
+		A: uint8(255),
+	}
+
+	for y := 0; y < height; y++ {
+		for x := 0; x < step; x = x + channels {
+			c.B = data[y*step+x]
+			c.G = data[y*step+x+1]
+			c.R = data[y*step+x+2]
+			//if channels == 4 {
+			//	c.A = data[y*step+x+3]
+			//}
+			img.SetRGBA(x/channels, y, c)
+		}
+	}
+
+	return img, nil
+}
+
+// ImageToJpeg save to jpeg data
+func ImageToJpeg(img image.Image, quality *int) ([]byte, error) {
+	var o *jpeg.Options
+
+	if quality != nil {
+		o = &jpeg.Options{Quality: *quality}
+	}
+	var b bytes.Buffer
+	w := bufio.NewWriter(&b)
+	err := jpeg.Encode(w, img, o)
+	if err != nil {
+		return nil, err
+	}
+	return b.Bytes(), err
+}
+
+// Image2BGR img->bgr
+func Image2BGR(img image.Image) []byte {
+	bounds := img.Bounds()
+	x := bounds.Dx()
+	y := bounds.Dy()
+	data := make([]byte, 0, x*y*3)
+	for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
+		for i := bounds.Min.X; i < bounds.Max.X; i++ {
+			r, g, b, _ := img.At(i, j).RGBA()
+			data = append(data, byte(b>>8), byte(g>>8), byte(r>>8))
+		}
+	}
+	return data
+}
+
+func DecodeBase64ToImage(data string) image.Image {
+	imgData, err := base64.StdEncoding.DecodeString(data)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	img, _, err := image.Decode(bytes.NewReader(imgData))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	return img
+}

--
Gitblit v1.8.0