-
-
Notifications
You must be signed in to change notification settings - Fork 130
Fix template scale in find element by image #307
Conversation
lib/basedriver/commands/find.js
Outdated
@@ -183,6 +183,9 @@ commands.findByCustom = async function (selector, multiple) { | |||
* image is merely to check staleness. If so we can bypass a lot of logic | |||
* @property {boolean} [multiple=false] - Whether we are finding one element or | |||
* multiple | |||
* @property {boolean} [ignoreDefaultImageTemplateScale=false] - Whether we | |||
* ignore defaultImageTemplateScale. It can be used when you would noe like to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
noe?
lib/basedriver/commands/find.js
Outdated
* @param {string} b64Template - base64-encoded image used as a template to be | ||
* matched in the screenshot | ||
* @param {ScreenshotScale} scale - scale of screen. Default to `{}` | ||
* @param {ScreenshotScale, ImageTemplateSettings} opts - Image template scale related options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather keep a single ImageTemplateSettings type here.
lib/basedriver/commands/find.js
Outdated
|
||
const defaultScale = 1.0; // To initialise xScale and yScale | ||
const defaultOpts = { | ||
fixImageTemplateScale: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can set defaults without _.defaults call:
const {
defaultImageTemplateScale: DEFAULT_TEMPLATE_IMAGE_SCALE,
...
} = opts;
lib/basedriver/commands/find.js
Outdated
return b64Template; | ||
} | ||
|
||
const defaultScale = 1.0; // To initialise xScale and yScale |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constants should be in uppercase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also it's better to move it out of the func
lib/basedriver/commands/find.js
Outdated
xScale = xScale * defaultImageTemplateScale; | ||
yScale = yScale * defaultImageTemplateScale; | ||
} else { | ||
// `1.0 *` makes NaN if defaultImageTemplateScale is no number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is not a number
lib/basedriver/commands/find.js
Outdated
const {xScale, yScale} = scale; | ||
// Calculate xScale and yScale Appium should scale | ||
if (opts.fixImageTemplateScale) { | ||
xScale = xScale * defaultImageTemplateScale; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use xScale *= defaultImageTemplateScale
lib/basedriver/commands/find.js
Outdated
if (!xScale || !yScale) { | ||
return b64Template; | ||
} | ||
|
||
// Return if the scale is deatul (1.0) value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deatul?
lib/basedriver/commands/find.js
Outdated
if (!xScale || !yScale) { | ||
return b64Template; | ||
} | ||
|
||
// Return if the scale is deatul (1.0) value | ||
if (xScale === defaultScale && yScale === defaultScale) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in general it is not a good idea to compare float values for equality
@@ -25,6 +25,14 @@ const GLOBAL_DEFAULT_SETTINGS = { | |||
// if a user use `width=750 × height=1334` pixels's base template image. | |||
fixImageTemplateScale: false, | |||
|
|||
// Users might have scaled template image to reduce their storage size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be nice to have this also described in some doc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I'm thinking to add this in https://github.com/appium/appium/blob/master/docs/en/advanced-concepts/image-elements.md
6b1c2c1
to
17cb7da
Compare
lib/basedriver/commands/find.js
Outdated
|
||
const screenAR = screenWidth / screenHeight; | ||
const shotAR = shotWidth / shotHeight; | ||
if (screenAR === shotAR) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/appium/appium-base-driver/pull/306/files#diff-a7d1893e663367145d766d1aaab4aad4L347 case.
I discussed with @jlipps and figure out the issue.
I left an example of this ratio issue as a comment below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
float comparison?
lib/basedriver/commands/find.js
Outdated
// Because if Appium selects the both ratio, the screenshot will be distorted. | ||
// If Appium selects the xScale, height will be bigger than real screenshot size | ||
// which is used to image comparison by OpenCV as a base image. | ||
const _xScale = (1.0 * shotWidth) / screenWidth; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need underscore prefixes?
return b64Template; | ||
} | ||
|
||
const {xScale, yScale} = scale; | ||
let { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
lib/basedriver/commands/find.js
Outdated
xScale *= defaultImageTemplateScale; | ||
yScale *= defaultImageTemplateScale; | ||
} else { | ||
// `1 *` makes NaN if defaultImageTemplateScale is not a number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think parseFloat would be more readable for such purpose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
> parseFloat('a')
NaN
ah... 👍
lib/basedriver/commands/find.js
Outdated
if (!xScale || !yScale) { | ||
return b64Template; | ||
} | ||
|
||
// Return if the scale is default (1.0) value | ||
if ((xScale - DEFAULT_FIX_IMAGE_TEMPLATE_SCALE) <= 0 && (yScale - DEFAULT_FIX_IMAGE_TEMPLATE_SCALE) === 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please avoid comparing float values for equality.
It is mandatory to have some delta epsilon value or use toFixed transformation and compare these as strings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/basedriver/commands/find.js
Outdated
@@ -12,6 +12,10 @@ const commands = {}, helpers = {}, extensions = {}; | |||
const IMAGE_STRATEGY = '-image'; | |||
const CUSTOM_STRATEGY = '-custom'; | |||
|
|||
// Used to compar ratio and screen width | |||
// Pixel is basically under 1080 for example. 100K is probably enough fo a while. | |||
const DEFAULT_ROUND_FLOAT = 100000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather rename it to FLOAT_PRECISION
lib/basedriver/commands/find.js
Outdated
|
||
|
||
const commands = {}, helpers = {}, extensions = {}; | ||
|
||
const IMAGE_STRATEGY = '-image'; | ||
const CUSTOM_STRATEGY = '-custom'; | ||
|
||
// Used to compar ratio and screen width | ||
// Pixel is basically under 1080 for example. 100K is probably enough fo a while. | ||
const FLOAT_PERCISION = 100000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PRECISION
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops...
lib/basedriver/commands/find.js
Outdated
@@ -357,42 +367,119 @@ helpers.getScreenshotForImageFind = async function (screenWidth, screenHeight) { | |||
// of coordinates returned by the image match algorithm, since we match based | |||
// on the screenshot coordinates not the device coordinates themselves. There | |||
// are two potential types of mismatch: aspect ratio mismatch and scale | |||
// mismatch. | |||
// mismatch. we need to detect and fix both |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We
Will wait for @jlipps to double check the comparison logic |
@jlipps Do you have a chance to have a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got some final questions for you, looks mostly good though
lib/basedriver/commands/find.js
Outdated
|
||
|
||
const commands = {}, helpers = {}, extensions = {}; | ||
|
||
const IMAGE_STRATEGY = '-image'; | ||
const CUSTOM_STRATEGY = '-custom'; | ||
|
||
// Used to compar ratio and screen width |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compare
lib/basedriver/commands/find.js
Outdated
const screenAR = screenWidth / screenHeight; | ||
const shotAR = shotWidth / shotHeight; | ||
if (Math.round(screenAR * FLOAT_PRECISION) === Math.round(shotAR * FLOAT_PRECISION)) { | ||
log.info('Screenshot aspect ratio matched screen aspect ratio'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice to do something like 'Screenshot aspect ratio (${shotAR}) matched screen aspect ratio (${screenAR})'
lib/basedriver/commands/find.js
Outdated
`is ${screenWidth}x${screenHeight} whereas screenshot is ` + | ||
`${shotWidth}x${shotHeight}.`); | ||
|
||
// Select smaller ratio |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// In the case where the x-scale and y-scale are different, we need to decide
// which one to respect, otherwise the screenshot and template will end up
// being resized in a way that changes its aspect ratio (distorts it). For example, let's say:
// this.getScreenshot(shotWidth, shotHeight) is 540x397,
// this.getDeviceSize(screenWidth, screenHeight) is 1080x1920.
// The ratio would then be {xScale: 0.5, yScale: 0.2}.
// In this case, we must should `yScale: 0.2` as scaleFactor, because
// If we select the xScale, the height will be bigger than real screenshot size
// which is used to image comparison by OpenCV as a base image.
// All of this is primarily useful when the screenshot is a horizontal slice taken out of the
// screen (for example not including top/bottom nav bars)
|
||
// Resize based on the screen dimensions only if both width and height are mismatched | ||
// since except for that, it might be a situation which is different window rect and | ||
// screenshot size like `@driver.window_rect #=>x=0, y=0, width=1080, height=1794` and | ||
// `"deviceScreenSize"=>"1080x1920"` | ||
let scale; | ||
if (screenWidth !== shotWidth && screenHeight !== shotHeight) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we be comparing the new imgObj width and height here? it looks like we're comparing against the old shotWidth/shotHeight, but those could have changed in the previous block, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. I added b536b10 to update shotWidth
and shotHeight
if they should have been updated in the ratio comparison
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jlipps Do you have a chance to take a look ^?
lib/basedriver/device-settings.js
Outdated
// Users might have scaled template image to reduce their storage size. | ||
// This setting allows users to scale a template image they send to Appium server | ||
// so that Appium server compare actual scale users orginaly have. | ||
// e.g. A user have `270 × 32 pixels` image oridinally `1080 × 126 pixels` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
originally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a user has an image of 270 x 32 pixels which was originally 1080 x 126 pixels
lib/basedriver/device-settings.js
Outdated
@@ -25,6 +25,14 @@ const GLOBAL_DEFAULT_SETTINGS = { | |||
// if a user use `width=750 × height=1334` pixels's base template image. | |||
fixImageTemplateScale: false, | |||
|
|||
// Users might have scaled template image to reduce their storage size. | |||
// This setting allows users to scale a template image they send to Appium server | |||
// so that Appium server compare actual scale users orginaly have. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so that the Appium server compares the actual scale users originally had
lib/basedriver/device-settings.js
Outdated
// This setting allows users to scale a template image they send to Appium server | ||
// so that Appium server compare actual scale users orginaly have. | ||
// e.g. A user have `270 × 32 pixels` image oridinally `1080 × 126 pixels` | ||
// The user set {defaultImageTemplateScale: 4.0} to scale the small image |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user can set
Fix remaining issue in https://github.com/appium/appium-base-driver/pull/306/files#r261480026 .
In the PR, I fixed a template image had different width/height with device screen, but it can be fixed scaling them up/down upto match to device width/height.
But the ratio issue has also below case.
example:
750 x 1314 pixels
image to187 x 328 pixels
in order to decrease their storage when he store the template image.To resolve the case, I introduced
defaultImageTemplateScale
. If the user setsdefaultImageTemplateScale: 4
for example, Appium will scale the template image up 4 times by default. Then, users do not need to scale in user side.It can use with
fixImageTemplateScale
for example. It can help to handle some cases such as I described as #306cc @jlipps