refactor: remove opencv

This commit is contained in:
lilong.129
2024-08-31 01:13:08 +08:00
parent 3186e353a5
commit 3e17d48e5a
9 changed files with 4 additions and 861 deletions

View File

@@ -7,23 +7,10 @@ From v4.3.0HttpRunner will support mobile UI automation testing:
Some UI recognition algorithms are also introduced for both iOS and Android:
- OpenCV: based on [OpenCV 4], with golang bindings [hybridgroup/gocv] and helper utils [electricbubble/gwda-ext-opencv]
- OCR: based on OCR API service from [volcengine], other API service may be extended
## Dependencies
### OpenCV
[OpenCV 4] should be pre-installed.
You can install OpenCV 4.6.0 using Homebrew on macOS.
```bash
$ brew install opencv
```
You can get more installation introduction on [hybridgroup/gocv].
### OCR
OCR API is a paid service, you need to pre-purchase and configure the environment variables.
@@ -36,16 +23,12 @@ OCR API is a paid service, you need to pre-purchase and configure the environmen
This uixt module is initially forked from the following repos and made a lot of changes.
- [electricbubble/gwda-ext-opencv]
- [electricbubble/gwda]
- [electricbubble/guia2]
[electricbubble/gwda-ext-opencv]: https://github.com/electricbubble/gwda-ext-opencv
[appium/WebDriverAgent]: https://github.com/appium/WebDriverAgent
[electricbubble/gwda]: https://github.com/electricbubble/gwda
[electricbubble/guia2]: https://github.com/electricbubble/guia2
[OpenCV 4]: https://opencv.org/
[hybridgroup/gocv]: https://github.com/hybridgroup/gocv
[volcengine]: https://www.volcengine.com/product/text-recognition
[appium-uiautomator2-server]: https://github.com/appium/appium-uiautomator2-server

View File

@@ -678,9 +678,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) (err error) {
return fmt.Errorf("invalid %s params: %v", ACTION_TapByOCR, action.Params)
case ACTION_TapByCV:
actionOptions := NewActionOptions(action.GetOptions()...)
if imagePath, ok := action.Params.(string); ok {
return dExt.TapByCV(imagePath, action.GetOptions()...)
} else if len(actionOptions.ScreenShotWithUITypes) > 0 {
if len(actionOptions.ScreenShotWithUITypes) > 0 {
return dExt.TapByUIDetection(action.GetOptions()...)
}
return fmt.Errorf("invalid %s params: %v", ACTION_TapByCV, action.Params)

View File

@@ -1,20 +0,0 @@
//go:build localtest
package uixt
import (
"testing"
)
func TestDriverExt_Drag(t *testing.T) {
driverExt, err := iosDevice.NewDriver()
checkErr(t, err)
pathSearch := "/Users/hero/Documents/temp/2020-05/opencv/IMG_map.png"
// err = driverExt.Drag(pathSearch, 300, 500, 2)
// checkErr(t, err)
err = driverExt.DragOffset(pathSearch, 300, 500, 2.1, 0.5, 2)
checkErr(t, err)
}

View File

@@ -20,33 +20,10 @@ import (
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v4/hrp/code"
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
"github.com/httprunner/httprunner/v4/hrp/internal/env"
)
// TemplateMatchMode is the type of the template matching operation.
type TemplateMatchMode int
type CVArgs struct {
matchMode TemplateMatchMode
threshold float64
}
type CVOption func(*CVArgs)
func WithTemplateMatchMode(mode TemplateMatchMode) CVOption {
return func(args *CVArgs) {
args.matchMode = mode
}
}
func WithThreshold(threshold float64) CVOption {
return func(args *CVArgs) {
args.threshold = threshold
}
}
type cacheStepData struct {
// cache step screenshot paths
screenShots []string
@@ -63,7 +40,6 @@ func (d *cacheStepData) reset() {
}
type DriverExt struct {
CVArgs
Device Device
Driver WebDriver
WindowSize Size
@@ -93,12 +69,6 @@ func newDriverExt(device Device, driver WebDriver, options ...DriverOption) (dEx
interruptSignal: make(chan os.Signal, 1),
}
err = dExt.extendCV()
if err != nil {
return nil, errors.Wrap(code.MobileUIDriverError,
fmt.Sprintf("extend OpenCV failed: %v", err))
}
dExt.cacheStepData.reset()
signal.Notify(dExt.interruptSignal, syscall.SIGTERM, syscall.SIGINT)
dExt.doneMjpegStream = make(chan bool, 1)
@@ -218,8 +188,8 @@ func (dExt *DriverExt) FindUIRectInUIKit(search string, options ...ActionOption)
if !isPathExists(search) {
return dExt.FindScreenText(search, options...)
}
// click on image, using opencv
return dExt.FindImageRectInUIKit(search, options...)
err = errors.New("ocr text not found")
return
}
func (dExt *DriverExt) AssertOCR(text, assert string) bool {
@@ -243,21 +213,6 @@ func (dExt *DriverExt) AssertOCR(text, assert string) bool {
return false
}
func (dExt *DriverExt) AssertImage(imagePath, assert string) bool {
var err error
switch assert {
case AssertionExists:
_, err = dExt.FindImageRectInUIKit(imagePath)
return err == nil
case AssertionNotExists:
_, err = dExt.FindImageRectInUIKit(imagePath)
return err != nil
default:
log.Warn().Str("assert method", assert).Msg("unexpected assert method")
}
return false
}
func (dExt *DriverExt) AssertForegroundApp(appName, assert string) bool {
app, err := dExt.Driver.GetForegroundApp()
if err != nil {
@@ -283,8 +238,6 @@ func (dExt *DriverExt) DoValidation(check, assert, expected string, message ...s
switch check {
case SelectorOCR:
result = dExt.AssertOCR(expected, assert)
case SelectorImage:
result = dExt.AssertImage(expected, assert)
case SelectorForegroundApp:
result = dExt.AssertForegroundApp(expected, assert)
}

View File

@@ -1,466 +0,0 @@
//go:build opencv
package uixt
import (
"bytes"
"fmt"
"image"
"image/color"
"io"
"math"
"os"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"gocv.io/x/gocv"
)
const (
// TmCcoeffNormed maps to TM_CCOEFF_NORMED
TmCcoeffNormed TemplateMatchMode = iota
// TmSqdiff maps to TM_SQDIFF
TmSqdiff
// TmSqdiffNormed maps to TM_SQDIFF_NORMED
TmSqdiffNormed
// TmCcorr maps to TM_CCORR
TmCcorr
// TmCcorrNormed maps to TM_CCORR_NORMED
TmCcorrNormed
// TmCcoeff maps to TM_CCOEFF
TmCcoeff
)
type DebugMode int
const (
// DmOff no output
DmOff DebugMode = iota
// DmEachMatch output matched and mismatched values
DmEachMatch
// DmNotMatch output only values that do not match
DmNotMatch
)
// extendCV 获得扩展后的 Driver
// 并指定匹配阀值,
// 获取当前设备的 Scale
// 默认匹配模式为 TmCcoeffNormed
// 默认关闭 OpenCV 匹配值计算后的输出
func (dExt *DriverExt) extendCV(options ...CVOption) (err error) {
for _, option := range options {
option(&dExt.CVArgs)
}
if dExt.threshold == 0 {
dExt.threshold = 0.95 // default threshold
}
if dExt.matchMode == 0 {
dExt.matchMode = TmCcoeffNormed // default match mode
}
Debug(DebugMode(DmOff))
return
}
func (dExt *DriverExt) Debug(dm DebugMode) {
Debug(DebugMode(dm))
}
func (dExt *DriverExt) OnlyOnceThreshold(threshold float64) (newExt *DriverExt) {
newExt = new(DriverExt)
newExt.Driver = dExt.Driver
newExt.matchMode = dExt.matchMode
newExt.threshold = threshold
return
}
func (dExt *DriverExt) OnlyOnceMatchMode(matchMode TemplateMatchMode) (newExt *DriverExt) {
newExt = new(DriverExt)
newExt.Driver = dExt.Driver
newExt.matchMode = matchMode
newExt.threshold = dExt.threshold
return
}
// func (sExt *DriverExt) findImgRect(search string) (rect image.Rectangle, err error) {
// pathSource := filepath.Join(sExt.pathname, GenFilename())
// if err = sExt.driver.ScreenshotToDisk(pathSource); err != nil {
// return image.Rectangle{}, err
// }
//
// if rect, err = FindImageRectFromDisk(pathSource, search, float32(sExt.Threshold), TemplateMatchMode(sExt.MatchMode)); err != nil {
// return image.Rectangle{}, err
// }
// return
// }
func (dExt *DriverExt) FindAllImageRect(search string) (rects []image.Rectangle, err error) {
var bufSource, bufSearch *bytes.Buffer
if bufSearch, err = getBufFromDisk(search); err != nil {
return nil, err
}
screenResult, err := dExt.GetScreenResult()
if err != nil {
return nil, err
}
bufSource = screenResult.bufSource
if rects, err = FindAllImageRectsFromRaw(bufSource, bufSearch, float32(dExt.threshold), TemplateMatchMode(dExt.matchMode)); err != nil {
return nil, err
}
return
}
func (dExt *DriverExt) FindImageRectInUIKit(imagePath string, options ...ActionOption) (point PointF, err error) {
var bufSource, bufSearch *bytes.Buffer
if bufSearch, err = getBufFromDisk(imagePath); err != nil {
return PointF{}, err
}
var rect image.Rectangle
if rect, err = FindImageRectFromRaw(bufSource, bufSearch, float32(dExt.threshold), TemplateMatchMode(dExt.matchMode)); err != nil {
return PointF{}, err
}
point = getRectangleCenterPoint(rect)
return point, nil
}
func getBufFromDisk(name string) (*bytes.Buffer, error) {
var f *os.File
var err error
if f, err = os.Open(name); err != nil {
return nil, err
}
var all []byte
if all, err = io.ReadAll(f); err != nil {
return nil, err
}
return bytes.NewBuffer(all), nil
}
var debug = DmOff
const dmOutputMsg = `[DEBUG] The current value is '%.4f', the expected value is '%.4f'`
func Debug(dm DebugMode) {
debug = dm
}
const DefaultMatchMode = TmCcoeffNormed
var fillColor = color.RGBA{R: 255, G: 255, B: 255, A: 0}
func FindImageLocationFromRaw(source, search *bytes.Buffer, threshold float32, matchMode ...TemplateMatchMode) (loc image.Point, err error) {
if len(matchMode) == 0 {
matchMode = []TemplateMatchMode{DefaultMatchMode}
}
var matImage, matTpl gocv.Mat
if matImage, matTpl, err = getMatsFromRaw(source, search, gocv.IMReadGrayScale); err != nil {
return image.Point{}, err
}
defer func() {
_ = matImage.Close()
_ = matTpl.Close()
}()
return getMatchingLocation(matImage, matTpl, threshold, matchMode[0])
}
func FindImageLocationFromDisk(source, search string, threshold float32, matchMode ...TemplateMatchMode) (loc image.Point, err error) {
if len(matchMode) == 0 {
matchMode = []TemplateMatchMode{DefaultMatchMode}
}
var matImage, matTpl gocv.Mat
if matImage, matTpl, err = getMatsFromDisk(source, search, gocv.IMReadGrayScale); err != nil {
return image.Point{}, err
}
defer func() {
_ = matImage.Close()
_ = matTpl.Close()
}()
return getMatchingLocation(matImage, matTpl, threshold, matchMode[0])
}
func FindAllImageLocationsFromDisk(source, search string, threshold float32, matchMode ...TemplateMatchMode) (locs []image.Point, err error) {
if len(matchMode) == 0 {
matchMode = []TemplateMatchMode{DefaultMatchMode}
}
var matImage, matTpl gocv.Mat
if matImage, matTpl, err = getMatsFromDisk(source, search, gocv.IMReadGrayScale); err != nil {
return nil, err
}
defer func() {
_ = matImage.Close()
_ = matTpl.Close()
}()
var loc image.Point
if loc, err = getMatchingLocation(matImage, matTpl, threshold, matchMode[0]); err != nil {
return nil, err
}
widthTpl := matTpl.Cols()
heightTpl := matTpl.Rows()
locs = make([]image.Point, 0, 9)
locs = append(locs, loc)
gocv.FillPoly(&matImage, gocv.NewPointsVectorFromPoints(getPts(loc, widthTpl, heightTpl)), fillColor)
loc, err = getMatchingLocation(matImage, matTpl, threshold, matchMode[0])
for ; err == nil; loc, err = getMatchingLocation(matImage, matTpl, threshold, matchMode[0]) {
locs = append(locs, loc)
gocv.FillPoly(&matImage, gocv.NewPointsVectorFromPoints(getPts(loc, widthTpl, heightTpl)), fillColor)
}
return locs, nil
}
func FindAllImageLocationsFromRaw(source, search *bytes.Buffer, threshold float32, matchMode ...TemplateMatchMode) (locs []image.Point, err error) {
if len(matchMode) == 0 {
matchMode = []TemplateMatchMode{DefaultMatchMode}
}
var matImage, matTpl gocv.Mat
if matImage, matTpl, err = getMatsFromRaw(source, search, gocv.IMReadGrayScale); err != nil {
return nil, err
}
defer func() {
_ = matImage.Close()
_ = matTpl.Close()
}()
var loc image.Point
if loc, err = getMatchingLocation(matImage, matTpl, threshold, matchMode[0]); err != nil {
return nil, err
}
widthTpl := matTpl.Cols()
heightTpl := matTpl.Rows()
locs = make([]image.Point, 0, 9)
locs = append(locs, loc)
gocv.FillPoly(&matImage, gocv.NewPointsVectorFromPoints(getPts(loc, widthTpl, heightTpl)), fillColor)
loc, err = getMatchingLocation(matImage, matTpl, threshold, matchMode[0])
for ; err == nil; loc, err = getMatchingLocation(matImage, matTpl, threshold, matchMode[0]) {
locs = append(locs, loc)
gocv.FillPoly(&matImage, gocv.NewPointsVectorFromPoints(getPts(loc, widthTpl, heightTpl)), fillColor)
}
return locs, nil
}
// getPts 根据图片坐标和宽高,获取填充区域
func getPts(loc image.Point, width, height int) [][]image.Point {
return [][]image.Point{
{
image.Pt(loc.X, loc.Y),
image.Pt(loc.X, loc.Y+height),
image.Pt(loc.X+width, loc.Y+height),
image.Pt(loc.X+width, loc.Y),
},
}
}
func FindImageRectFromDisk(source, search string, threshold float32, matchMode ...TemplateMatchMode) (rect image.Rectangle, err error) {
var matTpl gocv.Mat
if _, matTpl, err = getMatsFromDisk(source, search, gocv.IMReadGrayScale); err != nil {
return image.Rectangle{}, err
}
defer func() {
_ = matTpl.Close()
}()
var loc image.Point
if loc, err = FindImageLocationFromDisk(source, search, threshold, matchMode...); err != nil {
return image.Rectangle{}, err
}
rect = image.Rect(loc.X, loc.Y, loc.X+matTpl.Cols(), loc.Y+matTpl.Rows())
return
}
func FindAllImageRectsFromDisk(source, search string, threshold float32, matchMode ...TemplateMatchMode) (rects []image.Rectangle, err error) {
var matTpl gocv.Mat
if _, matTpl, err = getMatsFromDisk(source, search, gocv.IMReadGrayScale); err != nil {
return nil, err
}
defer func() {
_ = matTpl.Close()
}()
var locs []image.Point
if locs, err = FindAllImageLocationsFromDisk(source, search, threshold, matchMode...); err != nil {
return nil, err
}
rects = make([]image.Rectangle, 0, len(locs))
for i := range locs {
r := image.Rect(locs[i].X, locs[i].Y, locs[i].X+matTpl.Cols(), locs[i].Y+matTpl.Rows())
rects = append(rects, r)
}
return
}
func FindImageRectFromRaw(source, search *bytes.Buffer, threshold float32, matchMode ...TemplateMatchMode) (rect image.Rectangle, err error) {
var matTpl gocv.Mat
if _, matTpl, err = getMatsFromRaw(source, search, gocv.IMReadGrayScale); err != nil {
return image.Rectangle{}, err
}
defer func() {
_ = matTpl.Close()
}()
var loc image.Point
if loc, err = FindImageLocationFromRaw(source, search, threshold, matchMode...); err != nil {
return image.Rectangle{}, err
}
rect = image.Rect(loc.X, loc.Y, loc.X+matTpl.Cols(), loc.Y+matTpl.Rows())
return
}
func FindAllImageRectsFromRaw(source, search *bytes.Buffer, threshold float32, matchMode ...TemplateMatchMode) (rects []image.Rectangle, err error) {
var matTpl gocv.Mat
if _, matTpl, err = getMatsFromRaw(source, search, gocv.IMReadGrayScale); err != nil {
return nil, err
}
defer func() {
_ = matTpl.Close()
}()
var locs []image.Point
if locs, err = FindAllImageLocationsFromRaw(source, search, threshold, matchMode...); err != nil {
return nil, err
}
rects = make([]image.Rectangle, 0, len(locs))
for i := range locs {
r := image.Rect(locs[i].X, locs[i].Y, locs[i].X+matTpl.Cols(), locs[i].Y+matTpl.Rows())
rects = append(rects, r)
}
return
}
// getMatsFromDisk 从指定路径获取原图和目标图的 `gocv.Mat`
func getMatsFromDisk(nameImage, nameTpl string, flags gocv.IMReadFlag) (matImage, matTpl gocv.Mat, err error) {
matImage = gocv.IMRead(nameImage, flags)
if matImage.Empty() {
return gocv.Mat{}, gocv.Mat{}, fmt.Errorf("invalid read %s", nameImage)
}
matTpl = gocv.IMRead(nameTpl, flags)
if matTpl.Empty() {
return gocv.Mat{}, gocv.Mat{}, fmt.Errorf("invalid read %s", nameTpl)
}
return
}
// func getBufsFromDisk(nameImage, nameTpl string) (bufImage, bufTpl *bytes.Buffer, err error) {
// getBuf := func(_name string) (*bytes.Buffer, error) {
// var f *os.File
// var e error
// if f, e = os.Open(_name); e != nil {
// return nil, e
// }
// var all []byte
// if all, e = io.ReadAll(f); e != nil {
// return nil, e
// }
// return bytes.NewBuffer(all), nil
// }
// if bufImage, err = getBuf(nameImage); err != nil {
// return nil, nil, err
// }
// if bufTpl, err = getBuf(nameTpl); err != nil {
// return nil, nil, err
// }
// return
// }
// getMatsFromRaw 获取原图和目标图的 `gocv.Mat`
func getMatsFromRaw(bufImage, bufTpl *bytes.Buffer, flags gocv.IMReadFlag) (matImage, matTpl gocv.Mat, err error) {
if matImage, err = gocv.IMDecode(bufImage.Bytes(), flags); err != nil {
return gocv.Mat{}, gocv.Mat{}, fmt.Errorf("invalid read %w", err)
}
if matImage.Empty() {
return gocv.Mat{}, gocv.Mat{}, errors.New("invalid read [source]")
}
if matTpl, err = gocv.IMDecode(bufTpl.Bytes(), flags); err != nil {
return gocv.Mat{}, gocv.Mat{}, fmt.Errorf("invalid read %w", err)
}
if matTpl.Empty() {
return gocv.Mat{}, gocv.Mat{}, errors.New("invalid read [template]")
}
return
}
// getMatchingLocation 获取匹配的图片位置
func getMatchingLocation(matImage gocv.Mat, matTpl gocv.Mat, threshold float32, matchMode TemplateMatchMode) (loc image.Point, err error) {
if threshold > 1 {
threshold = 1.0
}
// TM_SQDIFF该方法使用平方差进行匹配最好匹配为 0。值越大匹配结果越差。
// TM_SQDIFF_NORMED该方法使用归一化的平方差进行匹配最佳匹配也在结果为0处。
// TmCcoeff 将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列)。
minVal, maxVal, minLoc, maxLoc := getMatchingResult(matImage, matTpl, matchMode)
// fmt.Println(matchMode[0], "\t", minVal, maxVal, "\t", minLoc, maxLoc)
// fmt.Printf("%s\t %.10f \t %.10f \t %v \t %v \n", matchMode[0], minVal, maxVal, minLoc, maxLoc)
var val float32
val, loc = getValLoc(minVal, maxVal, minLoc, maxLoc, matchMode)
if debug == DmEachMatch {
log.Debug().Msg(fmt.Sprintf(dmOutputMsg, val, threshold))
}
if val >= threshold {
return loc, nil
} else {
if debug == DmNotMatch {
log.Debug().Msg(fmt.Sprintf(dmOutputMsg, val, threshold))
}
return image.Point{}, errors.New("no such target search image")
}
}
// getMatchingResult 匹配图片并返回匹配值和位置
func getMatchingResult(matImage gocv.Mat, matTpl gocv.Mat, matchMode TemplateMatchMode) (minVal float32, maxVal float32, minLoc image.Point, maxLoc image.Point) {
matResult, tmpMask := gocv.NewMat(), gocv.NewMat()
defer func() {
_ = matResult.Close()
_ = tmpMask.Close()
}()
gocv.MatchTemplate(matImage, matTpl, &matResult, gocv.TemplateMatchMode(matchMode), tmpMask)
minVal, maxVal, minLoc, maxLoc = gocv.MinMaxLoc(matResult)
return
}
// getValLoc 根据不同的匹配模式返回匹配值和位置
func getValLoc(minVal float32, maxVal float32, minLoc image.Point, maxLoc image.Point, matchMode TemplateMatchMode) (val float32, loc image.Point) {
val, loc = maxVal, maxLoc
switch matchMode {
case TmSqdiff, TmSqdiffNormed:
// 平方差,最佳匹配为 0
val = minVal
// minVal = 8
// for val >= 1 {
// val -= 1
// }
if val >= 1 {
val = float32(math.Mod(float64(val), 1))
}
val = 1 - val
loc = minLoc
case TmCcoeff:
// TmCcoeff 将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列)。
// maxVal = 5064792.5000000000
_, frac := math.Modf(float64(val))
val = float32(frac)
case TmCcorr:
// maxVal = 50553512.0000000000
_, frac := math.Modf(float64(val))
val = float32(frac)
}
// fmt.Println("匹配度", val)
return
}

View File

@@ -1,23 +0,0 @@
//go:build !opencv
package uixt
import (
"image"
"github.com/rs/zerolog/log"
)
func (dExt *DriverExt) extendCV(options ...CVOption) (err error) {
return nil
}
func (dExt *DriverExt) FindAllImageRect(search string) (rects []image.Rectangle, err error) {
log.Fatal().Msg("opencv is not supported")
return
}
func (dExt *DriverExt) FindImageRectInUIKit(imagePath string, options ...ActionOption) (point PointF, err error) {
log.Fatal().Msg("opencv is not supported")
return
}

View File

@@ -1,259 +0,0 @@
//go:build opencv
package uixt
import (
"bytes"
"image"
"image/color"
"io/ioutil"
"sort"
"strconv"
"testing"
"gocv.io/x/gocv"
)
func TestFindImageLocation(t *testing.T) {
pathSource := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste_2020-05-18_16-20-31.png"
pathSearch := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste.png"
// pathSource = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5291.jpg"
// pathSearch = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5.png"
fileSource, err := ioutil.ReadFile(pathSource)
checkErr(t, err)
fileSearch, err := ioutil.ReadFile(pathSearch)
checkErr(t, err)
bufferSource := bytes.NewBuffer(fileSource)
bufferSearch := bytes.NewBuffer(fileSearch)
_, _ = bufferSource, bufferSearch
var imgLoc image.Point
// imgLoc, err := FindImageLocationFromRaw(bufferSource, bufferSearch, 0.95)
imgLoc, err = FindImageLocationFromDisk(pathSource, pathSearch, 0.95, TmSqdiff)
checkErr(t, err)
t.Log(imgLoc)
imgLoc, err = FindImageLocationFromDisk(pathSource, pathSearch, 0.95, TmSqdiffNormed)
checkErr(t, err)
t.Log(imgLoc)
// imgLoc, err = FindImageLocationFromDisk(pathSource, pathSearch, 0.95, gocv.TmCcoeff)
// checkErr(t, err)
// t.Log(imgLoc)
imgLoc, err = FindImageLocationFromDisk(pathSource, pathSearch, 0.95, TmCcoeffNormed)
checkErr(t, err)
t.Log(imgLoc)
// imgLoc, err = FindImageLocationFromDisk(pathSource, pathSearch, 0.95, gocv.TmCcorr)
// checkErr(t, err)
// t.Log(imgLoc)
imgLoc, err = FindImageLocationFromDisk(pathSource, pathSearch, 0.95, TmCcorrNormed)
checkErr(t, err)
t.Log(imgLoc)
return
window := gocv.NewWindow("Find Image")
defer window.Close()
blue := color.RGBA{R: 0, G: 0, B: 255, A: 0}
matBig := gocv.IMRead(pathSource, gocv.IMReadColor)
matTpl := gocv.IMRead(pathSearch, gocv.IMReadColor)
rect := image.Rect(imgLoc.X, imgLoc.Y, imgLoc.X+matTpl.Cols(), imgLoc.Y+matTpl.Rows())
gocv.Rectangle(&matBig, rect, blue, 3)
for {
window.IMShow(matBig)
if window.WaitKey(1) >= 0 {
break
}
}
}
func TestFindImageRectFromDisk(t *testing.T) {
pathSource := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste_2020-05-18_16-20-31.png"
pathSource = "/Users/hero/Documents/temp/2020-05/opencv/loop1.png"
// pathSource = "/Users/hero/Documents/temp/2020-05/opencv/loop2.png"
pathSearch := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste.png"
imgRect, err := FindImageRectFromDisk(pathSource, pathSearch, 0.95, TmCcorrNormed)
checkErr(t, err)
t.Log(imgRect)
// return
window := gocv.NewWindow("Find Image")
defer window.Close()
blue := color.RGBA{R: 0, G: 0, B: 255, A: 0}
matBig := gocv.IMRead(pathSource, gocv.IMReadColor)
gocv.Rectangle(&matBig, imgRect, blue, 3)
for {
window.IMShow(matBig)
if window.WaitKey(1) >= 0 {
break
}
}
}
func TestFindAllImageLocationsFromDisk(t *testing.T) {
pathSource := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste_2020-05-18_16-20-31.png"
pathSearch := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste.png"
pathSource = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5291.jpg"
pathSearch = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5.png"
locs, err := FindAllImageLocationsFromDisk(pathSource, pathSearch, 0.95)
checkErr(t, err)
t.Log(locs)
sort.Slice(locs, func(i, j int) bool {
if locs[i].Y < locs[j].Y {
return true
} else if locs[i].Y == locs[j].Y {
if locs[i].X < locs[j].X {
return true
}
}
return false
})
// return
window := gocv.NewWindow("Find Image")
defer window.Close()
blue := color.RGBA{R: 0, G: 0, B: 255, A: 0}
matBig := gocv.IMRead(pathSource, gocv.IMReadColor)
matTpl := gocv.IMRead(pathSearch, gocv.IMReadColor)
for i := range locs {
rect := image.Rect(locs[i].X, locs[i].Y, locs[i].X+matTpl.Cols(), locs[i].Y+matTpl.Rows())
gocv.Rectangle(&matBig, rect, blue, 3)
gocv.PutText(&matBig, strconv.FormatInt(int64(i), 10), locs[i], gocv.FontHersheySimplex, 2, blue, 3)
}
for {
window.IMShow(matBig)
if window.WaitKey(1) >= 0 {
break
}
}
}
func TestFindAllImageRectsFromDisk(t *testing.T) {
pathSource := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste_2020-05-18_16-20-31.png"
pathSearch := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste.png"
pathSource = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5291.jpg"
pathSearch = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5.png"
rects, err := FindAllImageRectsFromDisk(pathSource, pathSearch, 0.95)
checkErr(t, err)
t.Log(rects)
// return
window := gocv.NewWindow("Find Image")
defer window.Close()
blue := color.RGBA{R: 0, G: 0, B: 255, A: 0}
matBig := gocv.IMRead(pathSource, gocv.IMReadColor)
for i := range rects {
gocv.Rectangle(&matBig, rects[i], blue, 3)
gocv.PutText(&matBig, strconv.FormatInt(int64(i), 10), rects[i].Min, gocv.FontHersheySimplex, 2, blue, 3)
}
for {
window.IMShow(matBig)
if window.WaitKey(1) >= 0 {
break
}
}
}
func TestFindImageLocationFromRaw(t *testing.T) {
pathSource := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste_2020-05-18_16-20-31.png"
pathSearch := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste.png"
// pathSource = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5291.jpg"
// pathSearch = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5.png"
fileSource, err := ioutil.ReadFile(pathSource)
checkErr(t, err)
fileSearch, err := ioutil.ReadFile(pathSearch)
checkErr(t, err)
bufferSource := bytes.NewBuffer(fileSource)
bufferSearch := bytes.NewBuffer(fileSearch)
_, _ = bufferSource, bufferSearch
var imgLoc image.Point
// imgLoc, err := FindImageLocationFromRaw(bufferSource, bufferSearch, 0.95)
imgLoc, err = FindImageLocationFromRaw(bufferSource, bufferSearch, 0.95, TmSqdiff)
checkErr(t, err)
t.Log(imgLoc)
t.Log(FindImageRectFromRaw(bufferSource, bufferSearch, 0.95, TmSqdiff))
window := gocv.NewWindow("Find Image")
defer window.Close()
blue := color.RGBA{R: 0, G: 0, B: 255, A: 0}
matBig := gocv.IMRead(pathSource, gocv.IMReadColor)
matTpl := gocv.IMRead(pathSearch, gocv.IMReadColor)
rect := image.Rect(imgLoc.X, imgLoc.Y, imgLoc.X+matTpl.Cols(), imgLoc.Y+matTpl.Rows())
gocv.Rectangle(&matBig, rect, blue, 3)
for {
window.IMShow(matBig)
if window.WaitKey(1) >= 0 {
break
}
}
}
func TestFindAllImageRectsFromRaw(t *testing.T) {
pathSource := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste_2020-05-18_16-20-31.png"
pathSearch := "/Users/hero/Documents/temp/2020-05/opencv/Snipaste.png"
pathSource = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5291.jpg"
pathSearch = "/Users/hero/Documents/temp/2020-05/opencv/IMG_5.png"
fileSource, err := ioutil.ReadFile(pathSource)
checkErr(t, err)
fileSearch, err := ioutil.ReadFile(pathSearch)
checkErr(t, err)
bufferSource := bytes.NewBuffer(fileSource)
bufferSearch := bytes.NewBuffer(fileSearch)
_, _ = bufferSource, bufferSearch
rects, err := FindAllImageRectsFromRaw(bufferSource, bufferSearch, 0.95)
checkErr(t, err)
t.Log(rects)
sort.Slice(rects, func(i, j int) bool {
if rects[i].Min.Y < rects[j].Min.Y {
return true
} else if rects[i].Min.Y == rects[j].Min.Y {
if rects[i].Min.X < rects[j].Min.X {
return true
}
}
return false
})
// return
window := gocv.NewWindow("Find Image")
defer window.Close()
blue := color.RGBA{R: 0, G: 0, B: 255, A: 0}
matBig := gocv.IMRead(pathSource, gocv.IMReadColor)
for i := range rects {
gocv.Rectangle(&matBig, rects[i], blue, 3)
gocv.PutText(&matBig, strconv.FormatInt(int64(i), 10), rects[i].Min, gocv.FontHersheySimplex, 2, blue, 3)
}
for {
window.IMShow(matBig)
if window.WaitKey(1) >= 0 {
break
}
}
}

View File

@@ -47,20 +47,6 @@ func (dExt *DriverExt) TapByOCR(ocrText string, options ...ActionOption) error {
return dExt.TapAbsXY(point.X, point.Y, options...)
}
func (dExt *DriverExt) TapByCV(imagePath string, options ...ActionOption) error {
actionOptions := NewActionOptions(options...)
point, err := dExt.FindImageRectInUIKit(imagePath, options...)
if err != nil {
if actionOptions.IgnoreNotFoundError {
return nil
}
return err
}
return dExt.TapAbsXY(point.X, point.Y, options...)
}
func (dExt *DriverExt) TapByUIDetection(options ...ActionOption) error {
actionOptions := NewActionOptions(options...)