184 lines
3.9 KiB
Go
184 lines
3.9 KiB
Go
package clarity
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"image"
|
||
"runtime"
|
||
"sync"
|
||
|
||
"gocv.io/x/gocv"
|
||
"golang.org/x/sync/semaphore"
|
||
)
|
||
|
||
// 模糊检测器
|
||
type ConcurrentDetector struct {
|
||
maxWorkers int64 // 最大并发数
|
||
meanThreshold float64 // 均值阈值
|
||
laplaceStdThreshold float64 // Laplace标准差阈值
|
||
sem *semaphore.Weighted
|
||
}
|
||
|
||
type Option func(*ConcurrentDetector)
|
||
|
||
// 默认参数
|
||
func NewConcurrentDetector(opts ...Option) *ConcurrentDetector {
|
||
d := &ConcurrentDetector{
|
||
maxWorkers: int64(runtime.NumCPU() * 2),
|
||
meanThreshold: 5.0, // 原始值5
|
||
laplaceStdThreshold: 20.0, // 原始值20
|
||
}
|
||
|
||
for _, opt := range opts {
|
||
opt(d)
|
||
}
|
||
|
||
d.sem = semaphore.NewWeighted(d.maxWorkers)
|
||
return d
|
||
}
|
||
|
||
// 配置选项 -------------------------------------------------
|
||
func WithMeanThreshold(t float64) Option {
|
||
return func(d *ConcurrentDetector) {
|
||
d.meanThreshold = t
|
||
}
|
||
}
|
||
|
||
func WithLaplaceStdThreshold(t float64) Option {
|
||
return func(d *ConcurrentDetector) {
|
||
d.laplaceStdThreshold = t
|
||
}
|
||
}
|
||
|
||
func WithMaxWorkers(n int) Option {
|
||
return func(d *ConcurrentDetector) {
|
||
d.maxWorkers = int64(n)
|
||
}
|
||
}
|
||
|
||
func (d *ConcurrentDetector) ClarityCheck(img image.Image) (bool, error) {
|
||
if img == nil {
|
||
return false, fmt.Errorf("nil image input")
|
||
}
|
||
|
||
mat, err := gocv.ImageToMatRGB(img)
|
||
if err != nil || mat.Empty() {
|
||
if mat.Empty() == false {
|
||
mat.Close()
|
||
}
|
||
return false, err
|
||
}
|
||
matClone := mat.Clone()
|
||
if mat.Channels() != 1 {
|
||
gocv.CvtColor(mat, &matClone, gocv.ColorRGBToGray)
|
||
}
|
||
mat.Close()
|
||
|
||
// Canny检测部分
|
||
destCanny := gocv.NewMat()
|
||
defer destCanny.Close()
|
||
gocv.Canny(matClone, &destCanny, 200, 200)
|
||
|
||
destCannyC := gocv.NewMat()
|
||
defer destCannyC.Close()
|
||
destCannyD := gocv.NewMat()
|
||
defer destCannyD.Close()
|
||
gocv.MeanStdDev(destCanny, &destCannyC, &destCannyD)
|
||
if destCannyD.GetDoubleAt(0, 0) == 0 {
|
||
matClone.Close()
|
||
return false, nil
|
||
}
|
||
|
||
// Laplace检测部分
|
||
destA := gocv.NewMat()
|
||
defer destA.Close()
|
||
gocv.Laplacian(matClone, &destA, gocv.MatTypeCV64F, 3, 1, 0, gocv.BorderDefault)
|
||
|
||
destC := gocv.NewMat()
|
||
defer destC.Close()
|
||
destD := gocv.NewMat()
|
||
defer destD.Close()
|
||
gocv.MeanStdDev(destA, &destC, &destD)
|
||
|
||
destMean := gocv.NewMat()
|
||
defer destMean.Close()
|
||
gocv.Laplacian(matClone, &destMean, gocv.MatTypeCV16U, 3, 1, 0, gocv.BorderDefault)
|
||
mean := destMean.Mean()
|
||
matClone.Close()
|
||
|
||
// 使用可配置阈值(mean.Val1 >5 || destD.GetDoubleAt>20)
|
||
result := mean.Val1 > d.meanThreshold && destD.GetDoubleAt(0, 0) > d.laplaceStdThreshold
|
||
return result, nil
|
||
}
|
||
|
||
type Result struct {
|
||
Blurred bool
|
||
Err error
|
||
}
|
||
|
||
func (d *ConcurrentDetector) BatchDetect(ctx context.Context, images <-chan image.Image) <-chan Result {
|
||
results := make(chan Result)
|
||
var wg sync.WaitGroup
|
||
|
||
go func() {
|
||
defer close(results)
|
||
for img := range images {
|
||
if err := d.sem.Acquire(ctx, 1); err != nil {
|
||
break
|
||
}
|
||
wg.Add(1)
|
||
|
||
go func(img image.Image) {
|
||
defer wg.Done()
|
||
defer d.sem.Release(1)
|
||
|
||
blurred, err := d.ClarityCheck(img)
|
||
select {
|
||
case results <- Result{Blurred: blurred, Err: err}:
|
||
case <-ctx.Done():
|
||
}
|
||
}(img)
|
||
}
|
||
wg.Wait()
|
||
}()
|
||
|
||
return results
|
||
}
|
||
|
||
/*
|
||
func main() {
|
||
// 初始化检测器(调整阈值参数)
|
||
detector := NewConcurrentDetector(
|
||
WithMeanThreshold(8.0), // 提高均值阈值
|
||
WithLaplaceStdThreshold(25.0), // 提高标准差阈值
|
||
WithMaxWorkers(8), // 设置并发数
|
||
)
|
||
|
||
// 准备测试图片
|
||
img := loadImage("test.jpg")
|
||
|
||
// 单张检测
|
||
blurred, _ := detector.clarityCheck(img)
|
||
fmt.Println("Blurred:", blurred)
|
||
|
||
// 批量检测
|
||
ctx := context.Background()
|
||
imgChan := make(chan image.Image, 10)
|
||
go func() {
|
||
for i := 0; i < 10; i++ {
|
||
imgChan <- loadImage(fmt.Sprintf("image%d.jpg", i))
|
||
}
|
||
close(imgChan)
|
||
}()
|
||
|
||
results := detector.BatchDetect(ctx, imgChan)
|
||
for res := range results {
|
||
if res.Err != nil {
|
||
fmt.Println("Error:", res.Err)
|
||
continue
|
||
}
|
||
fmt.Println("Result:", res.Blurred)
|
||
}
|
||
}
|
||
*/
|