Skip to content

Commit b15b37f

Browse files
Merge pull request #1508 from VWS-Python/processed-tracking-rating-callable
Processed tracking rating - more realistic
2 parents 823b13f + 967fbce commit b15b37f

File tree

8 files changed

+30
-35
lines changed

8 files changed

+30
-35
lines changed

docs/source/differences-to-vws.rst

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,13 @@ Image quality and ratings
2929
-------------------------
3030

3131
Targets are assigned a rating between 0 and 5 of how good they are for tracking purposes.
32-
In the mock this is a random number between 0 and 5.
32+
In the mock this is calculated from the image quality, differently to how Vuforia does this.
3333

3434
Image targets which are not suited to detection are given 'failed' statuses.
3535
The criteria for these images is not defined by the Vuforia documentation.
3636
The mock is more forgiving than the real Vuforia Web Services.
3737
Therefore, an image given a 'success' status by the mock may not be given a 'success' status by the real Vuforia Web Services.
3838

39-
When updating an image for a target on the real Vuforia Web Services, the rating may stay the same.
40-
The mock changes the rating for a target to a different random number when the image is changed.
41-
4239
Matching targets in the processing state
4340
----------------------------------------
4441

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ warn_untyped_fields = true
140140
[[tool.mypy.overrides]]
141141

142142
module = [
143+
"brisque",
143144
"docker",
144145
"docker.errors",
145146
"docker.models.networks",
@@ -250,8 +251,10 @@ readme = { file = "README.rst", content-type = "text/x-rst"}
250251
requires-python = ">=3.10"
251252
dependencies = [
252253
"Pillow",
254+
"brisque",
253255
"flask",
254256
"multipart",
257+
"numpy",
255258
"pydantic",
256259
"requests",
257260
"requests-mock",
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
FROM python:3.11-slim-buster
2+
RUN apt update && apt install -y gcc g++ libgl1-mesa-glx libglib2.0-0
23
# We set this pretend version as we do not have Git in our path, and we do
34
# not care enough about having the version correct inside the Docker container
45
# to install it.
56
ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0
67
ENV TARGET_MANAGER_HOST=0.0.0.0
78
COPY . /app
89
WORKDIR /app
9-
RUN pip install .
10+
RUN pip install --upgrade .
1011
EXPOSE 5000
1112
ENTRYPOINT ["python"]
1213
CMD ["src/mock_vws/_flask_server/target_manager.py"]
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
FROM python:3.11-slim-buster
2+
RUN apt update && apt install -y gcc g++ libgl1-mesa-glx libglib2.0-0
23
# We set this pretend version as we do not have Git in our path, and we do
34
# not care enough about having the version correct inside the Docker container
45
# to install it.
56
ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0
67
ENV VWQ_HOST=0.0.0.0
78
COPY . /app
89
WORKDIR /app
9-
RUN pip install .
10+
RUN pip install --upgrade .
1011
EXPOSE 5000
1112
ENTRYPOINT ["python"]
1213
CMD ["src/mock_vws/_flask_server/vwq.py"]
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
FROM python:3.11-slim-buster
2+
RUN apt update && apt install -y gcc g++ libgl1-mesa-glx libglib2.0-0
23
COPY . /app
34
# We set this pretend version as we do not have Git in our path, and we do
45
# not care enough about having the version correct inside the Docker container
56
# to install it.
67
ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0
78
ENV VWS_HOST=0.0.0.0
89
WORKDIR /app
9-
RUN pip install .
10+
RUN pip install --upgrade .
1011
EXPOSE 5000
1112
ENTRYPOINT ["python"]
1213
CMD ["src/mock_vws/_flask_server/vws.py"]

src/mock_vws/_flask_server/target_manager.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import base64
66
import dataclasses
77
import datetime
8-
import random
98
from http import HTTPStatus
109
from zoneinfo import ZoneInfo
1110

@@ -212,12 +211,6 @@ def update_target(database_name: str, target_id: str) -> tuple[str, int]:
212211
if "image" in request.json:
213212
image_value = base64.b64decode(s=request.json["image"])
214213

215-
# In the real implementation, the tracking rating can stay the same.
216-
# However, for demonstration purposes, the tracking rating changes but
217-
# when the target is updated.
218-
available_values = list(set(range(6)) - {target.tracking_rating})
219-
processed_tracking_rating = random.choice(available_values)
220-
221214
gmt = ZoneInfo("GMT")
222215
last_modified_date = datetime.datetime.now(tz=gmt)
223216

@@ -228,7 +221,6 @@ def update_target(database_name: str, target_id: str) -> tuple[str, int]:
228221
active_flag=active_flag,
229222
application_metadata=application_metadata,
230223
image_value=image_value,
231-
processed_tracking_rating=processed_tracking_rating,
232224
last_modified_date=last_modified_date,
233225
)
234226

src/mock_vws/_requests_mock_server/mock_web_services_api.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import dataclasses
1212
import datetime
1313
import email.utils
14-
import random
1514
import uuid
1615
from http import HTTPStatus
1716
from typing import TYPE_CHECKING
@@ -590,12 +589,6 @@ def update_target(
590589
context.status_code = fail_exception.status_code
591590
return fail_exception.response_text
592591

593-
# In the real implementation, the tracking rating can stay the same.
594-
# However, for demonstration purposes, the tracking rating changes but
595-
# when the target is updated.
596-
available_values = list(set(range(6)) - {target.tracking_rating})
597-
processed_tracking_rating = random.choice(available_values)
598-
599592
gmt = ZoneInfo("GMT")
600593
last_modified_date = datetime.datetime.now(tz=gmt)
601594

@@ -606,7 +599,6 @@ def update_target(
606599
active_flag=active_flag,
607600
application_metadata=application_metadata,
608601
image_value=image_value,
609-
processed_tracking_rating=processed_tracking_rating,
610602
last_modified_date=last_modified_date,
611603
)
612604

src/mock_vws/target.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
import base64
77
import datetime
88
import io
9-
import random
9+
import math
1010
import statistics
1111
import uuid
1212
from dataclasses import dataclass, field
1313
from typing import TypedDict
1414
from zoneinfo import ZoneInfo
1515

16+
import brisque
17+
import numpy as np
1618
from PIL import Image, ImageStat
1719

1820
from mock_vws._constants import TargetStatuses
@@ -28,7 +30,6 @@ class TargetDict(TypedDict):
2830
image_base64: str
2931
active_flag: bool
3032
processing_time_seconds: int | float
31-
processed_tracking_rating: int
3233
application_metadata: str | None
3334
target_id: str
3435
last_modified_date: str
@@ -51,11 +52,24 @@ def _time_now() -> datetime.datetime:
5152
return datetime.datetime.now(tz=gmt)
5253

5354

54-
def _random_tracking_rating() -> int:
55+
def _quality(image_content: bytes) -> int:
5556
"""
56-
Return a random tracking rating.
57+
Args:
58+
image_content: The image content.
59+
60+
Returns:
61+
The quality of the image.
5762
"""
58-
return random.randint(0, 5)
63+
image_file = io.BytesIO(initial_bytes=image_content)
64+
image = Image.open(fp=image_file)
65+
image_array = np.asarray(a=image)
66+
obj = brisque.BRISQUE(url=False)
67+
# We avoid a barrage of warnings from the BRISQUE library.
68+
with np.errstate(divide="ignore", invalid="ignore"):
69+
score = obj.score(img=image_array)
70+
if math.isnan(score):
71+
return 0
72+
return int(score / 20)
5973

6074

6175
@dataclass(frozen=True, eq=True)
@@ -75,9 +89,6 @@ class Target:
7589
delete_date: datetime.datetime | None = None
7690
last_modified_date: datetime.datetime = field(default_factory=_time_now)
7791
previous_month_recos: int = 0
78-
processed_tracking_rating: int = field(
79-
default_factory=_random_tracking_rating,
80-
)
8192
reco_rating: str = ""
8293
target_id: str = field(default_factory=_random_hex)
8394
total_recos: int = 0
@@ -158,7 +169,7 @@ def tracking_rating(self) -> int:
158169
return -1
159170

160171
if self._post_processing_status == TargetStatuses.SUCCESS:
161-
return self.processed_tracking_rating
172+
return _quality(image_content=self.image_value)
162173

163174
return 0
164175

@@ -173,7 +184,6 @@ def from_dict(cls, target_dict: TargetDict) -> Target:
173184
width = target_dict["width"]
174185
image_base64 = target_dict["image_base64"]
175186
image_value = base64.b64decode(image_base64)
176-
processed_tracking_rating = target_dict["processed_tracking_rating"]
177187
processing_time_seconds = target_dict["processing_time_seconds"]
178188
application_metadata = target_dict["application_metadata"]
179189
target_id = target_dict["target_id"]
@@ -202,7 +212,6 @@ def from_dict(cls, target_dict: TargetDict) -> Target:
202212
delete_date=delete_date,
203213
last_modified_date=last_modified_date,
204214
upload_date=upload_date,
205-
processed_tracking_rating=processed_tracking_rating,
206215
)
207216

208217
def to_dict(self) -> TargetDict:
@@ -221,7 +230,6 @@ def to_dict(self) -> TargetDict:
221230
"image_base64": image_base64,
222231
"active_flag": self.active_flag,
223232
"processing_time_seconds": self.processing_time_seconds,
224-
"processed_tracking_rating": self.processed_tracking_rating,
225233
"application_metadata": self.application_metadata,
226234
"target_id": self.target_id,
227235
"last_modified_date": self.last_modified_date.isoformat(),

0 commit comments

Comments
 (0)