zhangzengfei
2024-05-26 379c9650894921633f6a6c8cb5a14f12cef2f6e8
入侵抓拍转人脸添加小图
1个文件已添加
1个文件已修改
326 ■■■■■ 已修改文件
controller/captureCtl.go 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/image.go 264 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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)
    }
pkg/image.go
New file
@@ -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 按照宽边修改目标框为正方形
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
        // 调整后的正方形框超出图像边界时的处理
        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
        // 调整后的正方形框超出图像边界时的处理
        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,
        }
    }
    // 如果宽度和高度相等,则已经是正方形,直接返回原始矩形
    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
}