193 lines
4.8 KiB
Go
193 lines
4.8 KiB
Go
package slider
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"os"
|
|
|
|
"gocv.io/x/gocv"
|
|
)
|
|
|
|
func VerifySliderWidth(bgImgPath, sliderImgPath string) int {
|
|
// 检查背景图片文件是否存在
|
|
if _, err := os.Stat(bgImgPath); os.IsNotExist(err) {
|
|
return -1
|
|
}
|
|
|
|
// 检查滑块图片文件是否存在
|
|
if _, err := os.Stat(sliderImgPath); os.IsNotExist(err) {
|
|
return -1
|
|
}
|
|
|
|
// 读取背景图片
|
|
bgImg := gocv.IMRead(bgImgPath, gocv.IMReadColor)
|
|
if bgImg.Empty() {
|
|
return -1
|
|
}
|
|
defer bgImg.Close()
|
|
|
|
// 读取滑块图片(包含 alpha 通道)
|
|
sliderImgWithAlpha := gocv.IMRead(sliderImgPath, gocv.IMReadUnchanged)
|
|
if sliderImgWithAlpha.Empty() {
|
|
return -1
|
|
}
|
|
defer sliderImgWithAlpha.Close()
|
|
|
|
// 分离滑块图片的通道
|
|
channels := gocv.Split(sliderImgWithAlpha)
|
|
defer func() {
|
|
for i := range channels {
|
|
channels[i].Close()
|
|
}
|
|
}()
|
|
|
|
var sliderImg gocv.Mat
|
|
var mask gocv.Mat
|
|
|
|
// 如果有 alpha 通道(4通道),提取 mask
|
|
if len(channels) == 4 {
|
|
// 前3个通道是 BGR
|
|
sliderImg = gocv.NewMat()
|
|
defer sliderImg.Close()
|
|
gocv.Merge(channels[:3], &sliderImg)
|
|
|
|
// 使用 alpha 通道作为 mask
|
|
mask = channels[3].Clone()
|
|
defer mask.Close()
|
|
} else if len(channels) == 3 {
|
|
// 没有透明通道,直接使用原图
|
|
sliderImg = sliderImgWithAlpha.Clone()
|
|
defer sliderImg.Close()
|
|
mask = gocv.NewMat() // 空 mask
|
|
defer mask.Close()
|
|
} else {
|
|
return -1
|
|
}
|
|
|
|
// 创建结果矩阵用于存储匹配结果
|
|
result := gocv.NewMat()
|
|
defer result.Close()
|
|
|
|
// 直接在原图上使用模板匹配找到滑块位置
|
|
if mask.Empty() {
|
|
gocv.MatchTemplate(bgImg, sliderImg, &result, gocv.TmCcoeffNormed, gocv.NewMat())
|
|
} else {
|
|
// 带 mask 的模板匹配
|
|
gocv.MatchTemplate(bgImg, sliderImg, &result, gocv.TmCcoeffNormed, mask)
|
|
}
|
|
|
|
// 找到最佳匹配位置
|
|
_, maxVal, _, maxLoc := gocv.MinMaxLoc(result)
|
|
|
|
// 如果匹配度太低,返回 -1 表示失败
|
|
if maxVal < 0.6 {
|
|
return -1
|
|
}
|
|
|
|
// 获取原图上的 x 坐标,然后按比例缩放到目标尺寸
|
|
originalWidth := bgImg.Cols()
|
|
targetWidth := 280
|
|
scale := float64(targetWidth) / float64(originalWidth)
|
|
scaledX := int(float64(maxLoc.X) * scale)
|
|
|
|
// 返回缩放后的 x 坐标(滑块需要移动的距离)
|
|
return scaledX
|
|
}
|
|
|
|
// VerifySliderWidthByBase64 通过 base64 编码的图片计算滑块验证码需要移动的距离
|
|
// bgImgBase64: 背景图片的 base64 编码
|
|
// sliderImgBase64: 滑块图片的 base64 编码
|
|
// 返回: 滑块需要移动的 x 距离(已缩放到 280 宽度),失败返回 -1
|
|
func VerifySliderWidthByBase64(bgImgBase64, sliderImgBase64 string) int {
|
|
// 解码背景图片的 base64
|
|
bgImgData, err := base64.StdEncoding.DecodeString(bgImgBase64)
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
|
|
// 解码滑块图片的 base64
|
|
sliderImgData, err := base64.StdEncoding.DecodeString(sliderImgBase64)
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
|
|
// 从内存中读取背景图片
|
|
bgImg, err := gocv.IMDecode(bgImgData, gocv.IMReadColor)
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
if bgImg.Empty() {
|
|
return -1
|
|
}
|
|
defer bgImg.Close()
|
|
|
|
// 从内存中读取滑块图片(包含 alpha 通道)
|
|
sliderImgWithAlpha, err := gocv.IMDecode(sliderImgData, gocv.IMReadUnchanged)
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
if sliderImgWithAlpha.Empty() {
|
|
return -1
|
|
}
|
|
defer sliderImgWithAlpha.Close()
|
|
|
|
// 分离滑块图片的通道
|
|
channels := gocv.Split(sliderImgWithAlpha)
|
|
defer func() {
|
|
for i := range channels {
|
|
channels[i].Close()
|
|
}
|
|
}()
|
|
|
|
var sliderImg gocv.Mat
|
|
var mask gocv.Mat
|
|
|
|
// 如果有 alpha 通道(4通道),提取 mask
|
|
if len(channels) == 4 {
|
|
// 前3个通道是 BGR
|
|
sliderImg = gocv.NewMat()
|
|
defer sliderImg.Close()
|
|
gocv.Merge(channels[:3], &sliderImg)
|
|
|
|
// 使用 alpha 通道作为 mask
|
|
mask = channels[3].Clone()
|
|
defer mask.Close()
|
|
} else if len(channels) == 3 {
|
|
// 没有透明通道,直接使用原图
|
|
sliderImg = sliderImgWithAlpha.Clone()
|
|
defer sliderImg.Close()
|
|
mask = gocv.NewMat() // 空 mask
|
|
defer mask.Close()
|
|
} else {
|
|
return -1
|
|
}
|
|
|
|
// 创建结果矩阵用于存储匹配结果
|
|
result := gocv.NewMat()
|
|
defer result.Close()
|
|
|
|
// 直接在原图上使用模板匹配找到滑块位置
|
|
if mask.Empty() {
|
|
gocv.MatchTemplate(bgImg, sliderImg, &result, gocv.TmCcoeffNormed, gocv.NewMat())
|
|
} else {
|
|
// 带 mask 的模板匹配
|
|
gocv.MatchTemplate(bgImg, sliderImg, &result, gocv.TmCcoeffNormed, mask)
|
|
}
|
|
|
|
// 找到最佳匹配位置
|
|
_, maxVal, _, maxLoc := gocv.MinMaxLoc(result)
|
|
|
|
// 如果匹配度太低,返回 -1 表示失败
|
|
if maxVal < 0.6 {
|
|
return -1
|
|
}
|
|
|
|
// 获取原图上的 x 坐标,然后按比例缩放到目标尺寸
|
|
originalWidth := bgImg.Cols()
|
|
targetWidth := 280
|
|
scale := float64(targetWidth) / float64(originalWidth)
|
|
scaledX := int(float64(maxLoc.X) * scale)
|
|
|
|
// 返回缩放后的 x 坐标(滑块需要移动的距离)
|
|
return scaledX
|
|
}
|