diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c71ad62..11e557b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -81,4 +81,4 @@ Finally, append your name to the list of contributors below and in [Header.vue]( Big thank you to all the people who have already contributed to AIM! -Antti Oulasvirta, Samuli De Pascale, Janin Koch, Thomas Langerak, Jussi Jokinen, Kashyap Todi, Markku Laine, Manoj Kristhombuge, Yuxi Zhu, Aliaksei Miniukovich, Gregorio Palmas, Tino Weinkauf, Ai Nakajima, Valentin Ionita, Morteza Shiripour, Amir Hossein Kargaran, and Chuhan Jiao. +Antti Oulasvirta, Samuli De Pascale, Janin Koch, Thomas Langerak, Jussi Jokinen, Kashyap Todi, Markku Laine, Manoj Kristhombuge, Yuxi Zhu, Aliaksei Miniukovich, Gregorio Palmas, Tino Weinkauf, Ai Nakajima, Valentin Ionita, Morteza Shiripour, Amir Hossein Kargaran, Chuhan Jiao and Nafiseh Nikeghbal. diff --git a/backend/aim/metrics/m27/__init__.py b/backend/aim/metrics/m27/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/aim/metrics/m27/m27_quadtree_decomposition.py b/backend/aim/metrics/m27/m27_quadtree_decomposition.py new file mode 100644 index 0000000..69c604b --- /dev/null +++ b/backend/aim/metrics/m27/m27_quadtree_decomposition.py @@ -0,0 +1,743 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Metric: + Quadtree decomposition + + +Description: + Quadtree decomposition for 3 aesthetic dimensions including balance, symmetry, + and equilibrium. Number of quadtree decomposition leaves is an indicator of visual complexity. + + Balance: the distribution of optical weight in a picture. + Optical weight refers to the perception that some objects appear heavier than + others. Larger objects are heavier, whereas small objects are lighter. Balance in + screen design is achieved by providing an equal weight of screen elements, left + and right, top and bottom. + + Symmetry: a unit on one side of the centre line is exactly + replicated on the other side. Vertical symmetry refers to the balanced arrangement + of equivalent elements about a vertical axis, and horizontal symmetry + about a horizontal axis. Radial symmetry consists of equivalent elements + balanced about two or more axes that intersect at a central point. In two seperate studies + this metric has not proven to be significant. + + Equilibrium: a stabilisation, a midway centre of suspension. Equilibrium + on a screen is accomplished through centring the layout itself. The centre of the + layout coincides with that of the frame. + + +Funding information and contact: + This work was funded by Technology Industries of Finland in a three-year + project grant on self-optimizing web services. The principal investigator + is Antti Oulasvirta (antti.oulasvirta@aalto.fi) of Aalto University. + + +References: + 1. Ngo, D., Teo, L. and Byrne, J. (2003). Modelling interface aesthetics. + Information Sciences 152, pp. 25-46. + doi: https://doi.org/10.1016/S0020-0255(02)00404-8 + + 2. Zheng, X., Chakraborty, I., Lin, J. and Rauschenberger, R. (2009) + Correlating Low-Level Image Statistics with Users' Rapid Aesthetic and + Affective Judgments of Web Pages. In Proceedings of the SIGCHI + Conference on Human Factors in Computing Systems (CHI'09 ~ Understanding + Information), pp. 1-10. ACM. + doi: https://doi.org/10.1145/1518701.1518703 + + 3. Reinecke, K., Yeh, T., Miratrix, L., Mardiko, R., Zhao, Y., Liu, J., and + Gajos, K. Z. (2013) Predicting Users' First Impressions of Website Aesthetics + With a Quantification of Perceived Visual Complexity and Colorfulness. In + Proceedings of the SIGCHI Conference on Human Factors in Computing Systems + (CHI'13), pp. 2049-2058, ACM. + doi: https://doi.org/10.1145/2470654.2481281 + + +Change log: + v2.0 (2023-01-01) + * Revised implementation + + v1.0.1 (2017-05-29) + * Initial implementation +""" + +# ---------------------------------------------------------------------------- +# Imports +# ---------------------------------------------------------------------------- + +# Standard library modules +import base64 +import math +from io import BytesIO +from typing import Any, Dict, List, Optional, Tuple, Union + +# Third-party modules +import cv2 +import matplotlib +import matplotlib.figure +import matplotlib.patches as patches +import matplotlib.pyplot as plt +import numpy as np +from PIL import Image +from pydantic import HttpUrl +from skimage import color + +# First-party modules +from aim.common import image_utils +from aim.common.constants import GUI_TYPE_DESKTOP +from aim.metrics.interfaces import AIMMetricInterface + +# ---------------------------------------------------------------------------- +# Metadata +# ---------------------------------------------------------------------------- + +__author__ = ( + "Amir Hossein Kargaran, Nafiseh Nikehgbal, Markku Laine, Thomas Langerak" +) +__date__ = "2023-01-01" +__email__ = "markku.laine@aalto.fi" +__version__ = "2.0" + + +# ---------------------------------------------------------------------------- +# Metric +# ---------------------------------------------------------------------------- + + +class Metric(AIMMetricInterface): + """ + Metric: Quadtree decomposition. + """ + + # Private constants + _SHOW: bool = False # show plot results of quadtree decomposition + + # _quadtree_color constants. thresolds are partially based on the paper, however it seems to be working different. + _COLOR_THRESH: int = ( + 55 # color entropy threshold. quite heavily website dependent + ) + _INTENSITY_THRESH: int = ( + 70 # intensity entropy threshold. based on nothing + ) + _L_BINS: int = 20 # luminince bins + _H_BINS: int = 30 # hue bins + _S_BINS: int = 32 # saturation bins + _MIN_NUM_DIVISION: int = ( + 2 # minumm number of quadtree decomposition devision + ) + _MIN_BLOCK_SIZE_H: int = 8 # minimum height of block + _MIN_BLOCK_SIZE_W: int = 8 # minimum width of block + + # _quadtree_gray constants. + _MIN_STD: int = ( + 20 # minimum STD threshold of each block for subsequent splitting + ) + _MIN_BLOCK_SIZE_GRAY: int = 25 # minimum size threshold of each block for subsequent splitting in pixel + + # Lists to save quadtree leaves, don't forget to empty them on the new image + _RES_LEAF_GRAY: List[Tuple[int, int, int, int]] = [] + _RES_LEAF_COLOR: List[Tuple[int, int, int, int]] = [] + + # Private methods + @staticmethod + def _balance( + leaves: List[Tuple[int, int, int, int]], width: int, height: int + ) -> float: + """ + Compute balance based on quadtree decomposition. + + Args: + leaves: quadtree decomposition leaves (List[Tuple[int, int, int, int]]) + width: width of image (int) + height: height of image (int) + + Return: + - balance dim (float) + """ + top: List[Tuple[int, int, int, int]] = [] + right: List[Tuple[int, int, int, int]] = [] + left: List[Tuple[int, int, int, int]] = [] + bottom: List[Tuple[int, int, int, int]] = [] + center: List[int] = [int(width / 2), int(height / 2)] + + for leaf in leaves: + if leaf[0] > center[0]: + right.append(leaf) + else: + left.append(leaf) + + if leaf[1] > center[1]: + bottom.append(leaf) + else: + top.append(leaf) + + w_left: float = 0.0 + w_top: float = 0.0 + w_bottom: float = 0.0 + w_right: float = 0.0 + + for leaf in top: + area: int = leaf[2] * leaf[3] + mid_point_leaf: List[int] = [ + int(leaf[0] + leaf[2] / 2), + int(leaf[1] + leaf[3] / 2), + ] + distance: int = abs(mid_point_leaf[0] - center[1]) + score: int = distance * area + w_top += score + + for leaf in bottom: + area = leaf[2] * leaf[3] + mid_point_leaf = [ + int(leaf[0] + leaf[2] / 2), + int(leaf[1] + leaf[3] / 2), + ] + distance = abs(mid_point_leaf[0] - center[1]) + score = distance * area + w_bottom += score + + for leaf in left: + area = leaf[2] * leaf[3] + mid_point_leaf = [ + int(leaf[0] + leaf[2] / 2), + int(leaf[1] + leaf[3] / 2), + ] + distance = abs(mid_point_leaf[1] - center[0]) + score = distance * area + w_left += score + + for leaf in right: + area = leaf[2] * leaf[3] + mid_point_leaf = [ + int(leaf[0] + leaf[2] / 2), + int(leaf[1] + leaf[3] / 2), + ] + distance = abs(mid_point_leaf[1] - center[0]) + score = distance * area + w_right += score + + IB_left_right: float = (w_left - w_right) / max( + abs(w_left), abs(w_right) + ) + IB_top_bottom: float = (w_top - w_bottom) / max( + abs(w_top), abs(w_bottom) + ) + BM: float = 1 - float(abs(IB_top_bottom) + abs(IB_left_right)) / 2 + + return BM + + @staticmethod + def _symmetry( + leaves: List[Tuple[int, int, int, int]], width: int, height: int + ) -> float: + """ + Compute symmetry based on quadtree decomposition. + + Args: + leaves: quadtree decomposition leaves (List[Tuple[int, int, int, int]]) + width: width of image (int) + height: height of image (int) + + Return: + - symmetry dim (float) + """ + UL_leaves: List[Tuple[int, int, int, int]] = [] + UR_leaves: List[Tuple[int, int, int, int]] = [] + LL_leaves: List[Tuple[int, int, int, int]] = [] + LR_leaves: List[Tuple[int, int, int, int]] = [] + + x_center: int = int(width / 2) + y_center: int = int(height / 2) + + for leaf in leaves: + if leaf[0] > x_center and leaf[1] < y_center: + UR_leaves.append(leaf) + elif leaf[0] <= x_center and leaf[1] < y_center: + UL_leaves.append(leaf) + elif leaf[0] > x_center and leaf[1] >= y_center: + LR_leaves.append(leaf) + elif leaf[0] <= x_center and leaf[1] >= y_center: + LL_leaves.append(leaf) + + X_j: List[float] = [] + Y_j: List[float] = [] + H_j: List[float] = [] + B_j: List[float] = [] + T_j: List[float] = [] + R_j: List[float] = [] + + # With j being respectively: UL;UR,LL;LR + for j in [UL_leaves, UR_leaves, LL_leaves, LR_leaves]: + X_score: float = 0.0 + Y_score: float = 0.0 + H_score: float = 0.0 + B_score: float = 0.0 + T_score: float = 0.0 + R_score: float = 0.0 + for leaf in j: + x_leaf: int = leaf[0] + int(leaf[2] / 2) + X_score += abs(x_leaf - x_center) + y_leaf: int = leaf[1] + int(leaf[3] / 2) + Y_score += abs(y_leaf - y_center) + H_score += leaf[3] + B_score += leaf[2] + T_score += int(abs(y_leaf - y_center) / abs(x_leaf - x_center)) + R_score += float( + (((x_leaf - x_center) ** 2) + ((y_leaf - y_center) ** 2)) + ** 0.5 + ) + + X_j.append(X_score) + Y_j.append(Y_score) + H_j.append(H_score) + B_j.append(B_score) + T_j.append(T_score) + R_j.append(R_score) + + # Normalize + X_j = [int(x / max(X_j)) for x in X_j] + Y_j = [int(y / max(Y_j)) for y in Y_j] + H_j = [int(h / max(H_j)) for h in H_j] + B_j = [int(b / max(B_j)) for b in B_j] + T_j = [int(t / max(T_j)) for t in T_j] + R_j = [float(r / max(R_j)) for r in R_j] + + SYM_ver: float = ( + abs(X_j[0] - X_j[1]) + + abs(X_j[2] - X_j[3]) + + abs(Y_j[0] - Y_j[1]) + + abs(Y_j[2] - Y_j[3]) + + abs(H_j[0] - H_j[1]) + + abs(H_j[2] - H_j[3]) + + abs(B_j[0] - B_j[1]) + + abs(B_j[2] - B_j[3]) + + abs(T_j[0] - T_j[1]) + + abs(T_j[2] - T_j[3]) + + abs(R_j[0] - R_j[1]) + + abs(R_j[2] - R_j[3]) + ) / 12 + + SYM_hor: float = ( + abs(X_j[0] - X_j[2]) + + abs(X_j[1] - X_j[3]) + + abs(Y_j[0] - Y_j[2]) + + abs(Y_j[1] - Y_j[3]) + + abs(H_j[0] - H_j[2]) + + abs(H_j[1] - H_j[3]) + + abs(B_j[0] - B_j[2]) + + abs(B_j[1] - B_j[3]) + + abs(T_j[0] - T_j[2]) + + abs(T_j[1] - T_j[3]) + + abs(R_j[0] - R_j[2]) + + abs(R_j[1] - R_j[3]) + ) / 12 + + SYM_rot: float = ( + abs(X_j[0] - X_j[3]) + + abs(X_j[1] - X_j[2]) + + abs(Y_j[0] - Y_j[3]) + + abs(Y_j[1] - Y_j[2]) + + abs(H_j[0] - H_j[3]) + + abs(H_j[1] - H_j[2]) + + abs(B_j[0] - B_j[3]) + + abs(B_j[1] - B_j[2]) + + abs(T_j[0] - T_j[3]) + + abs(T_j[1] - T_j[2]) + + abs(R_j[0] - R_j[3]) + + abs(R_j[1] - R_j[2]) + ) / 12 + + SYM: float = 1 - (abs(SYM_ver) + abs(SYM_hor) + abs(SYM_rot)) / 3 + + return SYM + + @staticmethod + def _equilibrium( + leaves: List[Tuple[int, int, int, int]], width: int, height: int + ) -> float: + """ + Compute equilibrium based on quadtree decomposition. + + Args: + leaves: quadtree decomposition leaves (List[Tuple[int, int, int, int]]) + width: width of image (int) + height: height of image (int) + + Return: + - equilibrium dim (float) + + Note: + This implementation seems unreasonably high. However, this is the case in the paper as well. + """ + area: List[float] = [] + dx: List[float] = [] + dy: List[float] = [] + + for leaf in leaves: + area.append(float(leaf[2] * leaf[3])) + dx.append(abs(float(leaf[0] + leaf[2] / 2 - width / 2))) + dy.append(abs(float(leaf[1] + leaf[3] / 2 - height / 2))) + + sum_x: float = 0.0 + sum_y: float = 0.0 + + for n in range(len(dx)): + sum_x += area[n] * dx[n] + sum_y += area[n] * dx[n] + + EM_x: float = (2 * sum_x) / (width * len(leaves) * np.sum(area)) + EM_y: float = (2 * sum_y) / (height * len(leaves) * np.sum(area)) + + EM: float = 1 - float(abs(EM_x) + abs(EM_y)) / 2 + + return EM + + @classmethod + def _intensity_entropy(cls, inp: np.ndarray) -> float: + """ + Compute intensity entropy based on luminance (l in lab color space) + + Args: + inp: rgb image (np.ndarray) + + Return: + - intensity entropy value (float) + """ + inp_lab: np.ndarray = color.rgb2lab(inp) + L_list: List[float] = list(inp_lab[:, :, 0].flatten()) + + p: np.ndarray + p, _ = np.histogram( + L_list, bins=cls._L_BINS, range=(0, 100), density=True + ) + p = p.ravel() + p = p * 100.0 + p = p + 1e-12 + p_log: List[float] = [math.log(y) for y in p] + p_result: np.ndarray = p * p_log + result: float = np.sum(p_result) + + return result + + @classmethod + def _color_entropy(cls, inp: np.ndarray) -> float: + """ + Compute color entropy based on hue and saturation (h and s in hsv color space) + + Args: + inp: rgb image (np.ndarray) + + Return: + - color entropy value (float) + """ + inp = inp / 255.0 + inp_hsv: np.ndarray = color.rgb2hsv(inp) + H_list: List[float] = list(inp_hsv[:, :, 0].flatten() * 360.0) + S_list: List[float] = list(inp_hsv[:, :, 1].flatten() * 100.0) + + h: np.ndarray + s: np.ndarray + h, _ = np.histogram( + H_list, bins=cls._H_BINS, range=(0, 360), density=True + ) + s, _ = np.histogram( + S_list, bins=cls._S_BINS, range=(0, 100), density=True + ) + + h = h.ravel() + h = h * 100.0 + h = h + 1e-12 + h_log: List[float] = [math.log(y) for y in h] + h_result: np.ndarray = h * h_log + + s = s.ravel() + s = s * 100.0 + s = s + 1e-12 + s_log = [math.log(y) for y in s] + s_result: np.ndarray = s * s_log + result: float = abs(np.sum(h_result) + np.sum(s_result)) / 2 + + return result + + @classmethod + def _quadtree_color(cls, leaf, cor_size, i) -> None: + """ + Compute quadtree decomposition over colored image by considering the uncertainty + of color in a leaf, given the leaf. It decides whether to continue the recursion + based on the shannon entropy of image with the thresholds. + + Args: + leaf: gray img (np.ndarray) + cor_size: cordination (Tuple[int, int, int, int]) + i: number of recursion (int) + + Return: + None + """ + # Currently, RGB entropy is calculated and intensity. + # The papers also refer to textons. This is not implemented yet: + # Representing and Recognizing the Visual Appearance of Materials using Three-dimensional Textons + # THOMAS LEUNG AND JITENDRA MALIK, International Journal of Computer Vision 43(1), 29-44, 2001 + ent_color: float = cls._color_entropy(leaf) + ent_int: float = cls._intensity_entropy(leaf) + + height: int = leaf.shape[0] + width: int = leaf.shape[1] + c_height: int = int(height / 2) + c_width: int = int(width / 2) + + # If entropy fullfulls requirements + # or the website has not been divided in enough leaves + # and there is still room for division: + if ( + ( + ent_color < cls._COLOR_THRESH + or ent_int > cls._INTENSITY_THRESH + or i < cls._MIN_NUM_DIVISION + ) + and c_height > cls._MIN_BLOCK_SIZE_H + and c_width > cls._MIN_BLOCK_SIZE_W + ): + i += 1 + # Divide the leaf in 4 new leaves + new_leaf = [ + leaf[0:c_height, 0:c_width], + leaf[c_height:height, 0:c_width], + leaf[0:c_height, c_width:width], + leaf[c_height:height, c_width:width], + ] + + # Coordinates and size of each leaf + new_cor_size = [ + (cor_size[0] + 0, cor_size[1] + 0, c_width, c_height), + (cor_size[0] + 0, cor_size[1] + c_height, c_width, c_height), + (cor_size[0] + c_width, cor_size[1] + 0, c_width, c_height), + ( + cor_size[0] + c_width, + cor_size[1] + c_height, + c_width, + c_height, + ), + ] + for x in range(len(new_leaf)): + # Run recursively + cls._quadtree_color(new_leaf[x], new_cor_size[x], i) + else: + # If not, append the coordinates and size + cls._RES_LEAF_COLOR.append(cor_size) + return None + + @classmethod + def _quadtree_gray(cls, leaf_gray, x, y) -> None: + """ + Compute quadtree decomposition over gray image by evaluaing the std of image pixels. + It decides whether to perform or not the split of leaf by compraing std of image with the min std threshold. + + Args: + leaf_gray: gray img (np.ndarray) + x: x offset of the leaves to analyze + y: y offset of the leaves to analyze + + Return: + None + """ + h, w = leaf_gray.shape + _, std_float = cv2.meanStdDev(leaf_gray) + std: int = int(std_float) + + if std >= cls._MIN_STD and max(h, w) >= cls._MIN_BLOCK_SIZE_GRAY: + if w >= h: + # split along the X axis + # decompose for both images + w2 = int(w / 2) + leaf_gray1 = leaf_gray[0:h, 0:w2] + leaf_gray2 = leaf_gray[0:h, w2:] + cls._quadtree_gray(leaf_gray1, x, y) + cls._quadtree_gray(leaf_gray2, x + w2, y) + else: + # split along the Y axis + # decompose for both images + h2 = int(h / 2) + leaf_gray1 = leaf_gray[0:h2, 0:] + leaf_gray2 = leaf_gray[h2:, 0:] + cls._quadtree_gray(leaf_gray1, x, y) + cls._quadtree_gray(leaf_gray2, x, y + h2) + else: + cls._RES_LEAF_GRAY.append((x, y, w, h)) + return None + + @classmethod + def plot( + cls, + org_img: np.ndarray, + res_leaf: List[Tuple[int, int, int, int]], + edgecolor: str = "red", + facecolor: str = "none", + linewidth: int = 1, + inv_dpi: float = 1e-2, + ) -> matplotlib.figure.Figure: + """ + This function is used to generate a graphical representation of the QuadTree decomposition. + + Args: + org_img: original image (np.ndarray) + res_leaf: list of blcok leaves (List[Tuple[int, int, int, int]]) + edgecolor: color of the rectangles, default is red (str) + facecolor: color used for rectangles fills. Default is "none" (str) + linewidth: width in px of the rectangles' borders. Default is 1 (int) + inv_dpi: scale of figure. Default is 0.01 (float) + + Return: + plot image of the quadTree Decomposition (matplotlib.figure.Figure) + """ + + # create a new figure with inv_dpi of original image size + + if not cls._SHOW: + matplotlib.use("Agg") + + fig_size_w: float = float(org_img.shape[1] * inv_dpi) + fig_size_h: float = float(org_img.shape[0] * inv_dpi) + plt.figure(figsize=(fig_size_w, fig_size_h)) + plt.axis("off") # no axis + + fig = plt.imshow(org_img) # plot the original image + + # for each leaf block, crate the rectangle and add it to plot + for block in res_leaf: + rect = patches.Rectangle( + (block[0], block[1]), + block[2], + block[3], + linewidth=linewidth, + edgecolor=edgecolor, + facecolor=facecolor, + ) + fig.axes.add_patch(rect) + + if cls._SHOW: + plt.show() + + return fig.figure + + def _get_img_from_fig( + fig: matplotlib.figure.Figure, dpi: int = 100 + ) -> np.ndarray: + """ + Return a matplotlib figure as a numpy array. + + Args: + fig: Input matplotlib figure (matplotlib.figure.Figure) + dpi: Dots per inch (int) + + Returns: + Output array of an input figure + + Source: + https://stackoverflow.com/questions/7821518/matplotlib-save-plot-to-numpy-array + """ + buf: BytesIO = BytesIO() + fig.savefig(buf, format="png", dpi=dpi) + buf.seek(0) + img_buff: np.ndarray = np.frombuffer(buf.getvalue(), dtype=np.uint8) + buf.close() + img_arr_bgr: np.ndarray = cv2.imdecode(img_buff, 1) + im_arr_rgb: np.ndarray = cv2.cvtColor(img_arr_bgr, cv2.COLOR_BGR2RGB) + + return im_arr_rgb + + # Public methods + @classmethod + def execute_metric( + cls, + gui_image: str, + gui_type: int = GUI_TYPE_DESKTOP, + gui_segments: Optional[Dict[str, Any]] = None, + gui_url: Optional[HttpUrl] = None, + ) -> Optional[List[Union[int, float, str]]]: + """ + Execute the metric. + + Args: + gui_image: GUI image (PNG) encoded in Base64 + + Kwargs: + gui_type: GUI type, desktop = 0 (default), mobile = 1 + gui_segments: GUI segments (defaults to None) + gui_url: GUI URL (defaults to None) + + Returns: + Results (list of measures) + - balance dimension (float, [0, 1]) + - symmetry dimension (float, [0, 1]) + - equilibrium (int, [float, [0, 1])) + - number of leaves (float, [0, +inf)) + - Quadtree blocks - color entropy based (str, image (PNG) encoded in Base64) + - Quadtree blocks - gray std based (str, image (PNG) encoded in Base64) + """ + # Create PIL image + img: Image.Image = Image.open(BytesIO(base64.b64decode(gui_image))) + + # Convert image from ??? (should be RGBA) to RGB color space + img_rgb: Image.Image = img.convert("RGB") + img_rgb_nparray: np.ndarray = np.array(img_rgb) + + # Image Height and Width + _HEIGHT = img_rgb_nparray.shape[0] + _WIDTH = img_rgb_nparray.shape[1] + + # EMPTY Lists to save quadtree leaves + cls._RES_LEAF_GRAY = [] + cls._RES_LEAF_COLOR = [] + + # COLOR: Compute quadtree color + cls._quadtree_color( + leaf=img_rgb_nparray, cor_size=(0, 0, _WIDTH, _HEIGHT), i=0 + ) + # Compute quadtree image + fig_quadtree_color = cls.plot( + org_img=img_rgb_nparray, res_leaf=cls._RES_LEAF_COLOR + ) + quadtree_color_arr: np.ndarray = cls._get_img_from_fig( + fig_quadtree_color + ) + quadtree_color_im: Image.Image = Image.fromarray(quadtree_color_arr) + quadtree_color_b64: str = image_utils.to_png_image_base64( + quadtree_color_im + ) + + # GRAY: Convert img_rgb_nparray to gray scale + img_gray_nparray: np.ndarray = cv2.cvtColor( + img_rgb_nparray, cv2.COLOR_RGB2GRAY + ) + # Compute quadtree gray + cls._quadtree_gray(leaf_gray=img_gray_nparray, x=0, y=0) + # Compute quadtree image + fig_quadtree_gray = cls.plot(img_rgb_nparray, cls._RES_LEAF_GRAY) + quadtree_gray_arr: np.ndarray = cls._get_img_from_fig( + fig_quadtree_gray + ) + quadtree_gray_im: Image.Image = Image.fromarray(quadtree_gray_arr) + quadtree_gray_b64: str = image_utils.to_png_image_base64( + quadtree_gray_im + ) + + # Compute metrics for quadtree color: balance, symmetry, and equilibrium + balance_dim: float = cls._balance(cls._RES_LEAF_COLOR, _WIDTH, _HEIGHT) + symmetry_dim: float = cls._symmetry( + cls._RES_LEAF_COLOR, _WIDTH, _HEIGHT + ) + equilibrium_dim: float = cls._equilibrium( + cls._RES_LEAF_COLOR, _WIDTH, _HEIGHT + ) + num_leaves: int = len(cls._RES_LEAF_COLOR) + + return [ + balance_dim, + symmetry_dim, + equilibrium_dim, + num_leaves, + quadtree_color_b64, + quadtree_gray_b64, + ] diff --git a/backend/data/evaluations/ALEXA_500/m27_0_histogram.png b/backend/data/evaluations/ALEXA_500/m27_0_histogram.png new file mode 100644 index 0000000..dc14780 Binary files /dev/null and b/backend/data/evaluations/ALEXA_500/m27_0_histogram.png differ diff --git a/backend/data/evaluations/ALEXA_500/m27_1_histogram.png b/backend/data/evaluations/ALEXA_500/m27_1_histogram.png new file mode 100644 index 0000000..3c36c80 Binary files /dev/null and b/backend/data/evaluations/ALEXA_500/m27_1_histogram.png differ diff --git a/backend/data/evaluations/ALEXA_500/m27_2_histogram.png b/backend/data/evaluations/ALEXA_500/m27_2_histogram.png new file mode 100644 index 0000000..37881f7 Binary files /dev/null and b/backend/data/evaluations/ALEXA_500/m27_2_histogram.png differ diff --git a/backend/data/evaluations/ALEXA_500/m27_3_histogram.png b/backend/data/evaluations/ALEXA_500/m27_3_histogram.png new file mode 100644 index 0000000..c026e32 Binary files /dev/null and b/backend/data/evaluations/ALEXA_500/m27_3_histogram.png differ diff --git a/backend/data/tests/expected_results/m27_1_duckduckgo.com.png b/backend/data/tests/expected_results/m27_1_duckduckgo.com.png new file mode 100644 index 0000000..815c840 Binary files /dev/null and b/backend/data/tests/expected_results/m27_1_duckduckgo.com.png differ diff --git a/backend/data/tests/expected_results/m27_2_duckduckgo.com.png b/backend/data/tests/expected_results/m27_2_duckduckgo.com.png new file mode 100644 index 0000000..3eb4b07 Binary files /dev/null and b/backend/data/tests/expected_results/m27_2_duckduckgo.com.png differ diff --git a/backend/data/tests/input_values/duckduckgo.com.png b/backend/data/tests/input_values/duckduckgo.com.png new file mode 100644 index 0000000..8cf6cf1 Binary files /dev/null and b/backend/data/tests/input_values/duckduckgo.com.png differ diff --git a/backend/tests/metrics/test_m27.py b/backend/tests/metrics/test_m27.py new file mode 100644 index 0000000..b57fac8 --- /dev/null +++ b/backend/tests/metrics/test_m27.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Tests for the 'Quadtree decomposition' metric (m27). +""" + + +# ---------------------------------------------------------------------------- +# Imports +# ---------------------------------------------------------------------------- + +# Standard library modules +import pathlib +from typing import Any, List, Optional, Union + +# Third-party modules +import pytest + +# First-party modules +from aim.common import image_utils +from aim.metrics.m27.m27_quadtree_decomposition import Metric +from tests.common.constants import DATA_TESTS_INPUT_VALUES_DIR, IDIFF_TOLERANCE +from tests.common.utils import load_expected_result + +# ---------------------------------------------------------------------------- +# Metadata +# ---------------------------------------------------------------------------- + +__author__ = "Amir Hossein Kargaran, Markku Laine" +__date__ = "2023-01-01" +__email__ = "markku.laine@aalto.fi" +__version__ = "1.0" + + +# ---------------------------------------------------------------------------- +# Tests +# ---------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + ["input_value", "expected_results"], + [ + ("blue.png", [0.333333, 0.388862, 0.959375, 16]), + ( + "duckduckgo.com.png", + [ + 0.413586, + 0.477775, + 0.996961, + 214.0, + load_expected_result("m27_1_duckduckgo.com.png"), + load_expected_result("m27_2_duckduckgo.com.png"), + ], + ), + ], +) +def test_duadtree_decomposition_desktop( + input_value: str, expected_results: List[Any] +) -> None: + """ + Test Quadtree decomposition (desktop GUIs). + + Args: + input_value: GUI image file name + expected_results: Expected results (list of measures) + """ + # Build GUI image file path + gui_image_filepath: pathlib.Path = ( + pathlib.Path(DATA_TESTS_INPUT_VALUES_DIR) / input_value + ) + + # Read GUI image (PNG) + gui_image_png_base64: str = image_utils.read_image(gui_image_filepath) + + # Execute metric + result: Optional[List[Union[int, float, str]]] = Metric.execute_metric( + gui_image_png_base64 + ) + + # Test result + if ( + result is not None + and isinstance(result[0], float) + and isinstance(result[1], float) + and isinstance(result[2], float) + and isinstance(result[3], int) + and isinstance(result[4], str) + and isinstance(result[5], str) + ): + + assert [round(float(r), 6) for r in result[:4]] == expected_results[:4] + + if len(expected_results) == 6: + assert ( + image_utils.idiff(result[4], expected_results[4]) + <= IDIFF_TOLERANCE + ) + assert ( + image_utils.idiff(result[5], expected_results[5]) + <= IDIFF_TOLERANCE + ) diff --git a/frontend/src/assets/results/m27_results.json b/frontend/src/assets/results/m27_results.json new file mode 100644 index 0000000..3b3a973 --- /dev/null +++ b/frontend/src/assets/results/m27_results.json @@ -0,0 +1,2564 @@ +[ + { + "m27_0":0.6522, + "m27_1":0.5041, + "m27_2":0.9995, + "m27_3":1387 + }, + { + "m27_0":0.8342, + "m27_1":0.5576, + "m27_2":0.9996, + "m27_3":1840 + }, + { + "m27_0":0.6859, + "m27_1":0.4984, + "m27_2":0.9995, + "m27_3":1321 + }, + { + "m27_0":0.6738, + "m27_1":0.5093, + "m27_2":0.9995, + "m27_3":1441 + }, + { + "m27_0":0.859, + "m27_1":0.5484, + "m27_2":0.9998, + "m27_3":2617 + }, + { + "m27_0":0.8625, + "m27_1":0.5613, + "m27_2":0.9997, + "m27_3":2245 + }, + { + "m27_0":0.6626, + "m27_1":0.5039, + "m27_2":0.9996, + "m27_3":1549 + }, + { + "m27_0":0.7146, + "m27_1":0.4945, + "m27_2":0.9996, + "m27_3":1708 + }, + { + "m27_0":0.6721, + "m27_1":0.5217, + "m27_2":0.9997, + "m27_3":1942 + }, + { + "m27_0":0.694, + "m27_1":0.5584, + "m27_2":0.9996, + "m27_3":1729 + }, + { + "m27_0":0.6366, + "m27_1":0.5481, + "m27_2":0.9995, + "m27_3":1273 + }, + { + "m27_0":0.8902, + "m27_1":0.5476, + "m27_2":0.9998, + "m27_3":3190 + }, + { + "m27_0":0.4642, + "m27_1":0.4971, + "m27_2":0.9992, + "m27_3":853 + }, + { + "m27_0":0.607, + "m27_1":0.4929, + "m27_2":0.9997, + "m27_3":1978 + }, + { + "m27_0":0.381, + "m27_1":0.5011, + "m27_2":0.9965, + "m27_3":184 + }, + { + "m27_0":0.8941, + "m27_1":0.5322, + "m27_2":0.9997, + "m27_3":2341 + }, + { + "m27_0":0.8695, + "m27_1":0.5366, + "m27_2":0.9997, + "m27_3":2080 + }, + { + "m27_0":0.7422, + "m27_1":0.5399, + "m27_2":0.9997, + "m27_3":2152 + }, + { + "m27_0":0.7795, + "m27_1":0.543, + "m27_2":0.9997, + "m27_3":2125 + }, + { + "m27_0":0.806, + "m27_1":0.5122, + "m27_2":0.9994, + "m27_3":1180 + }, + { + "m27_0":0.6833, + "m27_1":0.5125, + "m27_2":0.9996, + "m27_3":1708 + }, + { + "m27_0":0.8377, + "m27_1":0.5103, + "m27_2":0.9997, + "m27_3":2209 + }, + { + "m27_0":0.8375, + "m27_1":0.5495, + "m27_2":0.9996, + "m27_3":1612 + }, + { + "m27_0":0.5601, + "m27_1":0.5106, + "m27_2":0.9995, + "m27_3":1291 + }, + { + "m27_0":0.7409, + "m27_1":0.5058, + "m27_2":0.9995, + "m27_3":1303 + }, + { + "m27_0":0.8362, + "m27_1":0.542, + "m27_2":0.9997, + "m27_3":2149 + }, + { + "m27_0":0.818, + "m27_1":0.543, + "m27_2":0.9997, + "m27_3":2101 + }, + { + "m27_0":0.8628, + "m27_1":0.4963, + "m27_2":0.9997, + "m27_3":1930 + }, + { + "m27_0":0.5646, + "m27_1":0.4976, + "m27_2":0.9994, + "m27_3":1096 + }, + { + "m27_0":0.799, + "m27_1":0.5403, + "m27_2":0.9997, + "m27_3":1927 + }, + { + "m27_0":0.7444, + "m27_1":0.5071, + "m27_2":0.9997, + "m27_3":2440 + }, + { + "m27_0":0.7688, + "m27_1":0.537, + "m27_2":0.9997, + "m27_3":2023 + }, + { + "m27_0":0.6656, + "m27_1":0.5228, + "m27_2":0.9995, + "m27_3":1357 + }, + { + "m27_0":0.7902, + "m27_1":0.5438, + "m27_2":0.9995, + "m27_3":1411 + }, + { + "m27_0":0.5261, + "m27_1":0.5163, + "m27_2":0.9994, + "m27_3":1087 + }, + { + "m27_0":0.333, + "m27_1":0.4881, + "m27_2":0.994, + "m27_3":109 + }, + { + "m27_0":0.6602, + "m27_1":0.5064, + "m27_2":0.9997, + "m27_3":1960 + }, + { + "m27_0":0.8735, + "m27_1":0.5439, + "m27_2":0.9998, + "m27_3":3208 + }, + { + "m27_0":0.5516, + "m27_1":0.498, + "m27_2":0.9993, + "m27_3":904 + }, + { + "m27_0":0.8128, + "m27_1":0.5246, + "m27_2":0.9996, + "m27_3":1495 + }, + { + "m27_0":0.5203, + "m27_1":0.4991, + "m27_2":0.9994, + "m27_3":1084 + }, + { + "m27_0":0.7767, + "m27_1":0.5454, + "m27_2":0.9997, + "m27_3":2176 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.5501, + "m27_1":0.5372, + "m27_2":0.9995, + "m27_3":1261 + }, + { + "m27_0":0.9071, + "m27_1":0.5111, + "m27_2":0.9998, + "m27_3":2683 + }, + { + "m27_0":0.7535, + "m27_1":0.5257, + "m27_2":0.9997, + "m27_3":2407 + }, + { + "m27_0":0.7795, + "m27_1":0.5101, + "m27_2":0.9996, + "m27_3":1666 + }, + { + "m27_0":0.4279, + "m27_1":0.4783, + "m27_2":0.9959, + "m27_3":160 + }, + { + "m27_0":0.9124, + "m27_1":0.564, + "m27_2":0.9998, + "m27_3":2926 + }, + { + "m27_0":0.8487, + "m27_1":0.5143, + "m27_2":0.9997, + "m27_3":2470 + }, + { + "m27_0":0.7332, + "m27_1":0.5586, + "m27_2":0.9995, + "m27_3":1420 + }, + { + "m27_0":0.9383, + "m27_1":0.5758, + "m27_2":0.9998, + "m27_3":3952 + }, + { + "m27_0":0.8343, + "m27_1":0.5562, + "m27_2":0.9997, + "m27_3":2215 + }, + { + "m27_0":0.8532, + "m27_1":0.5315, + "m27_2":0.9997, + "m27_3":2470 + }, + { + "m27_0":0.6219, + "m27_1":0.4803, + "m27_2":0.9995, + "m27_3":1357 + }, + { + "m27_0":0.3537, + "m27_1":0.5077, + "m27_2":0.999, + "m27_3":658 + }, + { + "m27_0":0.8044, + "m27_1":0.5758, + "m27_2":0.9998, + "m27_3":2989 + }, + { + "m27_0":0.8591, + "m27_1":0.5591, + "m27_2":0.9998, + "m27_3":2680 + }, + { + "m27_0":0.6821, + "m27_1":0.4974, + "m27_2":0.9997, + "m27_3":1918 + }, + { + "m27_0":0.6301, + "m27_1":0.4538, + "m27_2":0.9988, + "m27_3":559 + }, + { + "m27_0":0.4163, + "m27_1":0.4954, + "m27_2":0.999, + "m27_3":643 + }, + { + "m27_0":0.8679, + "m27_1":0.5081, + "m27_2":0.9997, + "m27_3":2254 + }, + { + "m27_0":0.4171, + "m27_1":0.5532, + "m27_2":0.9995, + "m27_3":1393 + }, + { + "m27_0":0.6688, + "m27_1":0.5035, + "m27_2":0.9996, + "m27_3":1621 + }, + { + "m27_0":0.6448, + "m27_1":0.5338, + "m27_2":0.9997, + "m27_3":1966 + }, + { + "m27_0":0.7395, + "m27_1":0.4894, + "m27_2":0.9994, + "m27_3":1159 + }, + { + "m27_0":0.8596, + "m27_1":0.495, + "m27_2":0.9996, + "m27_3":1648 + }, + { + "m27_0":0.8145, + "m27_1":0.5294, + "m27_2":0.9996, + "m27_3":1756 + }, + { + "m27_0":0.6798, + "m27_1":0.5171, + "m27_2":0.9997, + "m27_3":1999 + }, + { + "m27_0":0.7446, + "m27_1":0.5125, + "m27_2":0.9998, + "m27_3":2692 + }, + { + "m27_0":0.7179, + "m27_1":0.52, + "m27_2":0.9997, + "m27_3":2269 + }, + { + "m27_0":0.6804, + "m27_1":0.5017, + "m27_2":0.9988, + "m27_3":529 + }, + { + "m27_0":0.9221, + "m27_1":0.5585, + "m27_2":0.9998, + "m27_3":3139 + }, + { + "m27_0":0.585, + "m27_1":0.5047, + "m27_2":0.9995, + "m27_3":1198 + }, + { + "m27_0":0.858, + "m27_1":0.5106, + "m27_2":0.9996, + "m27_3":1615 + }, + { + "m27_0":0.8522, + "m27_1":0.5397, + "m27_2":0.9997, + "m27_3":2401 + }, + { + "m27_0":0.5088, + "m27_1":0.5419, + "m27_2":0.9994, + "m27_3":1183 + }, + { + "m27_0":0.6483, + "m27_1":0.5086, + "m27_2":0.9995, + "m27_3":1291 + }, + { + "m27_0":0.4112, + "m27_1":0.4797, + "m27_2":0.9992, + "m27_3":793 + }, + { + "m27_0":0.7431, + "m27_1":0.5273, + "m27_2":0.9998, + "m27_3":2821 + }, + { + "m27_0":0.8673, + "m27_1":0.5255, + "m27_2":0.9996, + "m27_3":1738 + }, + { + "m27_0":0.7475, + "m27_1":0.5186, + "m27_2":0.9994, + "m27_3":1171 + }, + { + "m27_0":0.3897, + "m27_1":0.4806, + "m27_2":0.9967, + "m27_3":196 + }, + { + "m27_0":0.4822, + "m27_1":0.4768, + "m27_2":0.9985, + "m27_3":445 + }, + { + "m27_0":0.579, + "m27_1":0.515, + "m27_2":0.9995, + "m27_3":1306 + }, + { + "m27_0":0.8685, + "m27_1":0.5537, + "m27_2":0.9997, + "m27_3":1903 + }, + { + "m27_0":0.8557, + "m27_1":0.5412, + "m27_2":0.9998, + "m27_3":2677 + }, + { + "m27_0":0.6706, + "m27_1":0.4899, + "m27_2":0.9992, + "m27_3":823 + }, + { + "m27_0":0.646, + "m27_1":0.5517, + "m27_2":0.9994, + "m27_3":1093 + }, + { + "m27_0":0.6432, + "m27_1":0.5339, + "m27_2":0.9994, + "m27_3":1102 + }, + { + "m27_0":0.8749, + "m27_1":0.5437, + "m27_2":0.9998, + "m27_3":2878 + }, + { + "m27_0":0.7307, + "m27_1":0.5639, + "m27_2":0.9997, + "m27_3":1939 + }, + { + "m27_0":0.7426, + "m27_1":0.567, + "m27_2":0.9998, + "m27_3":2686 + }, + { + "m27_0":0.596, + "m27_1":0.5038, + "m27_2":0.9995, + "m27_3":1306 + }, + { + "m27_0":0.4944, + "m27_1":0.5088, + "m27_2":0.9993, + "m27_3":901 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.5363, + "m27_1":0.4967, + "m27_2":0.9989, + "m27_3":616 + }, + { + "m27_0":0.3338, + "m27_1":0.4733, + "m27_2":0.994, + "m27_3":109 + }, + { + "m27_0":0.8547, + "m27_1":0.5137, + "m27_2":0.9995, + "m27_3":1426 + }, + { + "m27_0":0.8333, + "m27_1":0.5592, + "m27_2":0.9997, + "m27_3":2143 + }, + { + "m27_0":0.8836, + "m27_1":0.532, + "m27_2":0.9998, + "m27_3":2863 + }, + { + "m27_0":0.9057, + "m27_1":0.5432, + "m27_2":0.9997, + "m27_3":2056 + }, + { + "m27_0":0.7369, + "m27_1":0.5499, + "m27_2":0.9996, + "m27_3":1732 + }, + { + "m27_0":0.9282, + "m27_1":0.514, + "m27_2":0.9998, + "m27_3":3004 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.8917, + "m27_1":0.5325, + "m27_2":0.9997, + "m27_3":2587 + }, + { + "m27_0":0.5409, + "m27_1":0.5469, + "m27_2":0.9995, + "m27_3":1204 + }, + { + "m27_0":0.6235, + "m27_1":0.4938, + "m27_2":0.9995, + "m27_3":1240 + }, + { + "m27_0":0.7691, + "m27_1":0.5307, + "m27_2":0.9995, + "m27_3":1384 + }, + { + "m27_0":0.4136, + "m27_1":0.4778, + "m27_2":0.997, + "m27_3":214 + }, + { + "m27_0":0.783, + "m27_1":0.5192, + "m27_2":0.9997, + "m27_3":1906 + }, + { + "m27_0":0.8003, + "m27_1":0.567, + "m27_2":0.9996, + "m27_3":1630 + }, + { + "m27_0":0.79, + "m27_1":0.5538, + "m27_2":0.9997, + "m27_3":2035 + }, + { + "m27_0":0.8615, + "m27_1":0.547, + "m27_2":0.9997, + "m27_3":2212 + }, + { + "m27_0":0.7725, + "m27_1":0.5702, + "m27_2":0.9997, + "m27_3":2407 + }, + { + "m27_0":0.8589, + "m27_1":0.5296, + "m27_2":0.9997, + "m27_3":2074 + }, + { + "m27_0":0.9016, + "m27_1":0.5286, + "m27_2":0.9998, + "m27_3":2695 + }, + { + "m27_0":0.7122, + "m27_1":0.5372, + "m27_2":0.9996, + "m27_3":1588 + }, + { + "m27_0":0.6776, + "m27_1":0.5622, + "m27_2":0.9996, + "m27_3":1726 + }, + { + "m27_0":0.9032, + "m27_1":0.5396, + "m27_2":0.9997, + "m27_3":2587 + }, + { + "m27_0":0.8004, + "m27_1":0.5431, + "m27_2":0.9996, + "m27_3":1660 + }, + { + "m27_0":0.8711, + "m27_1":0.5477, + "m27_2":0.9997, + "m27_3":2554 + }, + { + "m27_0":0.3355, + "m27_1":0.5033, + "m27_2":0.9888, + "m27_3":58 + }, + { + "m27_0":0.4366, + "m27_1":0.4679, + "m27_2":0.9958, + "m27_3":154 + }, + { + "m27_0":0.927, + "m27_1":0.5461, + "m27_2":0.9998, + "m27_3":2875 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.5161, + "m27_1":0.4935, + "m27_2":0.9991, + "m27_3":694 + }, + { + "m27_0":0.8812, + "m27_1":0.5162, + "m27_2":0.9996, + "m27_3":1702 + }, + { + "m27_0":0.8287, + "m27_1":0.5535, + "m27_2":0.9996, + "m27_3":1810 + }, + { + "m27_0":0.5592, + "m27_1":0.5199, + "m27_2":0.9997, + "m27_3":2128 + }, + { + "m27_0":0.8389, + "m27_1":0.5235, + "m27_2":0.9997, + "m27_3":1879 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.9045, + "m27_1":0.5423, + "m27_2":0.9997, + "m27_3":2350 + }, + { + "m27_0":0.907, + "m27_1":0.5488, + "m27_2":0.9998, + "m27_3":2995 + }, + { + "m27_0":0.6279, + "m27_1":0.517, + "m27_2":0.9996, + "m27_3":1690 + }, + { + "m27_0":0.798, + "m27_1":0.5504, + "m27_2":0.9995, + "m27_3":1402 + }, + { + "m27_0":0.7426, + "m27_1":0.5528, + "m27_2":0.9998, + "m27_3":2986 + }, + { + "m27_0":0.9212, + "m27_1":0.5557, + "m27_2":0.9998, + "m27_3":3433 + }, + { + "m27_0":0.8868, + "m27_1":0.5388, + "m27_2":0.9998, + "m27_3":2596 + }, + { + "m27_0":0.6342, + "m27_1":0.5052, + "m27_2":0.9989, + "m27_3":619 + }, + { + "m27_0":0.7481, + "m27_1":0.507, + "m27_2":0.9996, + "m27_3":1504 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.8558, + "m27_1":0.5356, + "m27_2":0.9996, + "m27_3":1705 + }, + { + "m27_0":0.8233, + "m27_1":0.5225, + "m27_2":0.9997, + "m27_3":2188 + }, + { + "m27_0":0.9334, + "m27_1":0.5261, + "m27_2":0.9998, + "m27_3":3109 + }, + { + "m27_0":0.8174, + "m27_1":0.5419, + "m27_2":0.9997, + "m27_3":2548 + }, + { + "m27_0":0.5256, + "m27_1":0.5345, + "m27_2":0.9995, + "m27_3":1363 + }, + { + "m27_0":0.7087, + "m27_1":0.55, + "m27_2":0.9997, + "m27_3":2155 + }, + { + "m27_0":0.6802, + "m27_1":0.4976, + "m27_2":0.9995, + "m27_3":1306 + }, + { + "m27_0":0.7725, + "m27_1":0.5617, + "m27_2":0.9997, + "m27_3":2299 + }, + { + "m27_0":0.7022, + "m27_1":0.535, + "m27_2":0.9996, + "m27_3":1654 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.8907, + "m27_1":0.5639, + "m27_2":0.9998, + "m27_3":2767 + }, + { + "m27_0":0.7701, + "m27_1":0.4932, + "m27_2":0.9994, + "m27_3":1108 + }, + { + "m27_0":0.6184, + "m27_1":0.5122, + "m27_2":0.9997, + "m27_3":1951 + }, + { + "m27_0":0.7414, + "m27_1":0.5237, + "m27_2":0.9997, + "m27_3":2347 + }, + { + "m27_0":0.3525, + "m27_1":0.496, + "m27_2":0.9977, + "m27_3":283 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.8184, + "m27_1":0.5315, + "m27_2":0.9995, + "m27_3":1408 + }, + { + "m27_0":0.6823, + "m27_1":0.5338, + "m27_2":0.9995, + "m27_3":1255 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.7531, + "m27_1":0.5391, + "m27_2":0.9996, + "m27_3":1471 + }, + { + "m27_0":0.6169, + "m27_1":0.5221, + "m27_2":0.9993, + "m27_3":997 + }, + { + "m27_0":0.8227, + "m27_1":0.495, + "m27_2":0.9996, + "m27_3":1807 + }, + { + "m27_0":0.7879, + "m27_1":0.5277, + "m27_2":0.9995, + "m27_3":1390 + }, + { + "m27_0":0.8629, + "m27_1":0.5037, + "m27_2":0.9996, + "m27_3":1639 + }, + { + "m27_0":0.9357, + "m27_1":0.5335, + "m27_2":0.9998, + "m27_3":3313 + }, + { + "m27_0":0.5293, + "m27_1":0.5028, + "m27_2":0.9994, + "m27_3":1129 + }, + { + "m27_0":0.691, + "m27_1":0.5565, + "m27_2":0.9997, + "m27_3":1894 + }, + { + "m27_0":0.6624, + "m27_1":0.5202, + "m27_2":0.9996, + "m27_3":1603 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.8985, + "m27_1":0.5675, + "m27_2":0.9998, + "m27_3":3505 + }, + { + "m27_0":0.5262, + "m27_1":0.4777, + "m27_2":0.9994, + "m27_3":1087 + }, + { + "m27_0":0.753, + "m27_1":0.5017, + "m27_2":0.9997, + "m27_3":2212 + }, + { + "m27_0":0.8969, + "m27_1":0.5601, + "m27_2":0.9997, + "m27_3":2560 + }, + { + "m27_0":0.7845, + "m27_1":0.519, + "m27_2":0.9997, + "m27_3":2515 + }, + { + "m27_0":0.5298, + "m27_1":0.4996, + "m27_2":0.9994, + "m27_3":1072 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.7754, + "m27_1":0.5103, + "m27_2":0.9997, + "m27_3":1891 + }, + { + "m27_0":0.7312, + "m27_1":0.5171, + "m27_2":0.9997, + "m27_3":2020 + }, + { + "m27_0":0.8794, + "m27_1":0.5277, + "m27_2":0.9998, + "m27_3":2791 + }, + { + "m27_0":0.384, + "m27_1":0.4966, + "m27_2":0.9988, + "m27_3":523 + }, + { + "m27_0":0.5866, + "m27_1":0.4953, + "m27_2":0.9994, + "m27_3":1138 + }, + { + "m27_0":0.7094, + "m27_1":0.5181, + "m27_2":0.9994, + "m27_3":1060 + }, + { + "m27_0":0.7752, + "m27_1":0.5136, + "m27_2":0.9996, + "m27_3":1789 + }, + { + "m27_0":0.6998, + "m27_1":0.5174, + "m27_2":0.9996, + "m27_3":1699 + }, + { + "m27_0":0.7496, + "m27_1":0.486, + "m27_2":0.9995, + "m27_3":1282 + }, + { + "m27_0":0.941, + "m27_1":0.5253, + "m27_2":0.9998, + "m27_3":3118 + }, + { + "m27_0":0.8422, + "m27_1":0.5429, + "m27_2":0.9998, + "m27_3":2788 + }, + { + "m27_0":0.5573, + "m27_1":0.501, + "m27_2":0.9995, + "m27_3":1216 + }, + { + "m27_0":0.3979, + "m27_1":0.4758, + "m27_2":0.999, + "m27_3":631 + }, + { + "m27_0":0.9276, + "m27_1":0.5589, + "m27_2":0.9998, + "m27_3":3487 + }, + { + "m27_0":0.6224, + "m27_1":0.5144, + "m27_2":0.9993, + "m27_3":985 + }, + { + "m27_0":0.5045, + "m27_1":0.4997, + "m27_2":0.9995, + "m27_3":1192 + }, + { + "m27_0":0.8222, + "m27_1":0.4948, + "m27_2":0.9997, + "m27_3":2101 + }, + { + "m27_0":0.8157, + "m27_1":0.5664, + "m27_2":0.9998, + "m27_3":3127 + }, + { + "m27_0":0.5129, + "m27_1":0.4949, + "m27_2":0.9983, + "m27_3":385 + }, + { + "m27_0":0.8469, + "m27_1":0.5297, + "m27_2":0.9998, + "m27_3":2818 + }, + { + "m27_0":0.8091, + "m27_1":0.5196, + "m27_2":0.9996, + "m27_3":1681 + }, + { + "m27_0":0.77, + "m27_1":0.5162, + "m27_2":0.9996, + "m27_3":1624 + }, + { + "m27_0":0.8357, + "m27_1":0.5321, + "m27_2":0.9998, + "m27_3":3292 + }, + { + "m27_0":0.7088, + "m27_1":0.5427, + "m27_2":0.9997, + "m27_3":2455 + }, + { + "m27_0":0.7035, + "m27_1":0.5055, + "m27_2":0.9997, + "m27_3":2203 + }, + { + "m27_0":0.7331, + "m27_1":0.5552, + "m27_2":0.9996, + "m27_3":1756 + }, + { + "m27_0":0.6737, + "m27_1":0.5384, + "m27_2":0.9997, + "m27_3":2527 + }, + { + "m27_0":0.9193, + "m27_1":0.5605, + "m27_2":0.9998, + "m27_3":2629 + }, + { + "m27_0":0.7002, + "m27_1":0.5064, + "m27_2":0.9996, + "m27_3":1585 + }, + { + "m27_0":0.8453, + "m27_1":0.5415, + "m27_2":0.9997, + "m27_3":2260 + }, + { + "m27_0":0.654, + "m27_1":0.5484, + "m27_2":0.9995, + "m27_3":1216 + }, + { + "m27_0":0.8654, + "m27_1":0.5671, + "m27_2":0.9998, + "m27_3":2812 + }, + { + "m27_0":0.9137, + "m27_1":0.5517, + "m27_2":0.9998, + "m27_3":3607 + }, + { + "m27_0":0.6298, + "m27_1":0.4921, + "m27_2":0.9992, + "m27_3":844 + }, + { + "m27_0":0.3546, + "m27_1":0.4915, + "m27_2":0.9952, + "m27_3":136 + }, + { + "m27_0":0.7939, + "m27_1":0.5388, + "m27_2":0.9998, + "m27_3":2707 + }, + { + "m27_0":0.9293, + "m27_1":0.5365, + "m27_2":0.9998, + "m27_3":3334 + }, + { + "m27_0":0.8993, + "m27_1":0.5297, + "m27_2":0.9998, + "m27_3":3196 + }, + { + "m27_0":0.8512, + "m27_1":0.5208, + "m27_2":0.9997, + "m27_3":2410 + }, + { + "m27_0":0.8389, + "m27_1":0.5313, + "m27_2":0.9997, + "m27_3":2056 + }, + { + "m27_0":0.6225, + "m27_1":0.5249, + "m27_2":0.9997, + "m27_3":1942 + }, + { + "m27_0":0.7498, + "m27_1":0.5198, + "m27_2":0.9996, + "m27_3":1714 + }, + { + "m27_0":0.3667, + "m27_1":0.494, + "m27_2":0.9951, + "m27_3":133 + }, + { + "m27_0":0.7014, + "m27_1":0.5425, + "m27_2":0.9996, + "m27_3":1498 + }, + { + "m27_0":0.5925, + "m27_1":0.5114, + "m27_2":0.9995, + "m27_3":1288 + }, + { + "m27_0":0.3837, + "m27_1":0.4995, + "m27_2":0.9991, + "m27_3":730 + }, + { + "m27_0":0.5748, + "m27_1":0.5348, + "m27_2":0.9989, + "m27_3":586 + }, + { + "m27_0":0.6408, + "m27_1":0.4997, + "m27_2":0.9987, + "m27_3":505 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.8968, + "m27_1":0.5433, + "m27_2":0.9996, + "m27_3":1795 + }, + { + "m27_0":0.9384, + "m27_1":0.5604, + "m27_2":0.9998, + "m27_3":3733 + }, + { + "m27_0":0.8837, + "m27_1":0.5694, + "m27_2":0.9998, + "m27_3":3046 + }, + { + "m27_0":0.6158, + "m27_1":0.4994, + "m27_2":0.9992, + "m27_3":844 + }, + { + "m27_0":0.7251, + "m27_1":0.5337, + "m27_2":0.9996, + "m27_3":1714 + }, + { + "m27_0":0.7965, + "m27_1":0.5064, + "m27_2":0.9995, + "m27_3":1414 + }, + { + "m27_0":0.7006, + "m27_1":0.5006, + "m27_2":0.9991, + "m27_3":754 + }, + { + "m27_0":0.8009, + "m27_1":0.4971, + "m27_2":0.9997, + "m27_3":1918 + }, + { + "m27_0":0.8232, + "m27_1":0.5284, + "m27_2":0.9997, + "m27_3":2464 + }, + { + "m27_0":0.5843, + "m27_1":0.5123, + "m27_2":0.9993, + "m27_3":955 + }, + { + "m27_0":0.8402, + "m27_1":0.5397, + "m27_2":0.9996, + "m27_3":1825 + }, + { + "m27_0":0.7587, + "m27_1":0.5468, + "m27_2":0.9997, + "m27_3":2320 + }, + { + "m27_0":0.9159, + "m27_1":0.5628, + "m27_2":0.9998, + "m27_3":3151 + }, + { + "m27_0":0.7065, + "m27_1":0.5337, + "m27_2":0.9996, + "m27_3":1675 + }, + { + "m27_0":0.6241, + "m27_1":0.5152, + "m27_2":0.9994, + "m27_3":1054 + }, + { + "m27_0":0.6161, + "m27_1":0.5304, + "m27_2":0.9996, + "m27_3":1444 + }, + { + "m27_0":0.5993, + "m27_1":0.4867, + "m27_2":0.9994, + "m27_3":1045 + }, + { + "m27_0":0.8581, + "m27_1":0.5228, + "m27_2":0.9997, + "m27_3":2020 + }, + { + "m27_0":0.9319, + "m27_1":0.5474, + "m27_2":0.9998, + "m27_3":3517 + }, + { + "m27_0":0.6972, + "m27_1":0.5409, + "m27_2":0.9997, + "m27_3":1930 + }, + { + "m27_0":0.8957, + "m27_1":0.5765, + "m27_2":0.9998, + "m27_3":2920 + }, + { + "m27_0":0.6487, + "m27_1":0.4855, + "m27_2":0.9996, + "m27_3":1495 + }, + { + "m27_0":0.8423, + "m27_1":0.5443, + "m27_2":0.9997, + "m27_3":2122 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.8423, + "m27_1":0.5384, + "m27_2":0.9998, + "m27_3":2665 + }, + { + "m27_0":0.4824, + "m27_1":0.5177, + "m27_2":0.9992, + "m27_3":844 + }, + { + "m27_0":0.8946, + "m27_1":0.5035, + "m27_2":0.9997, + "m27_3":2089 + }, + { + "m27_0":0.8137, + "m27_1":0.505, + "m27_2":0.9995, + "m27_3":1408 + }, + { + "m27_0":0.8032, + "m27_1":0.5062, + "m27_2":0.9997, + "m27_3":2029 + }, + { + "m27_0":0.8309, + "m27_1":0.5577, + "m27_2":0.9997, + "m27_3":2140 + }, + { + "m27_0":0.4489, + "m27_1":0.4943, + "m27_2":0.9991, + "m27_3":760 + }, + { + "m27_0":0.727, + "m27_1":0.5499, + "m27_2":0.9995, + "m27_3":1243 + }, + { + "m27_0":0.5596, + "m27_1":0.5276, + "m27_2":0.9988, + "m27_3":544 + }, + { + "m27_0":0.8356, + "m27_1":0.5473, + "m27_2":0.9994, + "m27_3":1015 + }, + { + "m27_0":0.9236, + "m27_1":0.5321, + "m27_2":0.9998, + "m27_3":3046 + }, + { + "m27_0":0.5161, + "m27_1":0.5106, + "m27_2":0.9993, + "m27_3":874 + }, + { + "m27_0":0.5164, + "m27_1":0.48, + "m27_2":0.9972, + "m27_3":229 + }, + { + "m27_0":0.8962, + "m27_1":0.5286, + "m27_2":0.9998, + "m27_3":2641 + }, + { + "m27_0":0.5468, + "m27_1":0.5206, + "m27_2":0.9991, + "m27_3":754 + }, + { + "m27_0":0.8556, + "m27_1":0.539, + "m27_2":0.9998, + "m27_3":2653 + }, + { + "m27_0":0.6501, + "m27_1":0.5075, + "m27_2":0.9993, + "m27_3":928 + }, + { + "m27_0":0.9127, + "m27_1":0.5071, + "m27_2":0.9997, + "m27_3":2368 + }, + { + "m27_0":0.8274, + "m27_1":0.51, + "m27_2":0.9994, + "m27_3":1174 + }, + { + "m27_0":0.8232, + "m27_1":0.5504, + "m27_2":0.9997, + "m27_3":2401 + }, + { + "m27_0":0.6849, + "m27_1":0.5024, + "m27_2":0.999, + "m27_3":673 + }, + { + "m27_0":0.9206, + "m27_1":0.5274, + "m27_2":0.9998, + "m27_3":2962 + }, + { + "m27_0":0.9383, + "m27_1":0.5218, + "m27_2":0.9998, + "m27_3":2965 + }, + { + "m27_0":0.8782, + "m27_1":0.552, + "m27_2":0.9998, + "m27_3":3430 + }, + { + "m27_0":0.5982, + "m27_1":0.4731, + "m27_2":0.9995, + "m27_3":1333 + }, + { + "m27_0":0.8964, + "m27_1":0.5225, + "m27_2":0.9998, + "m27_3":3019 + }, + { + "m27_0":0.7217, + "m27_1":0.5412, + "m27_2":0.9996, + "m27_3":1522 + }, + { + "m27_0":0.5875, + "m27_1":0.5074, + "m27_2":0.9996, + "m27_3":1495 + }, + { + "m27_0":0.9045, + "m27_1":0.5122, + "m27_2":0.9997, + "m27_3":2197 + }, + { + "m27_0":0.8608, + "m27_1":0.5538, + "m27_2":0.9997, + "m27_3":2323 + }, + { + "m27_0":0.5637, + "m27_1":0.5242, + "m27_2":0.9995, + "m27_3":1282 + }, + { + "m27_0":0.7262, + "m27_1":0.5247, + "m27_2":0.9996, + "m27_3":1765 + }, + { + "m27_0":0.3333, + "m27_1":0.494, + "m27_2":0.9978, + "m27_3":292 + }, + { + "m27_0":0.7891, + "m27_1":0.5036, + "m27_2":0.9994, + "m27_3":1129 + }, + { + "m27_0":0.7234, + "m27_1":0.558, + "m27_2":0.9997, + "m27_3":2551 + }, + { + "m27_0":0.8988, + "m27_1":0.5228, + "m27_2":0.9998, + "m27_3":2641 + }, + { + "m27_0":0.7444, + "m27_1":0.5221, + "m27_2":0.9997, + "m27_3":2452 + }, + { + "m27_0":0.9328, + "m27_1":0.5342, + "m27_2":0.9998, + "m27_3":3295 + }, + { + "m27_0":0.854, + "m27_1":0.553, + "m27_2":0.9997, + "m27_3":2140 + }, + { + "m27_0":0.7541, + "m27_1":0.5041, + "m27_2":0.9996, + "m27_3":1567 + }, + { + "m27_0":0.91, + "m27_1":0.4995, + "m27_2":0.9998, + "m27_3":2785 + }, + { + "m27_0":0.8738, + "m27_1":0.5625, + "m27_2":0.9998, + "m27_3":3283 + }, + { + "m27_0":0.7278, + "m27_1":0.4966, + "m27_2":0.9995, + "m27_3":1198 + }, + { + "m27_0":0.346, + "m27_1":0.4969, + "m27_2":0.9978, + "m27_3":292 + }, + { + "m27_0":0.8305, + "m27_1":0.5239, + "m27_2":0.9997, + "m27_3":1897 + }, + { + "m27_0":0.7163, + "m27_1":0.4824, + "m27_2":0.9995, + "m27_3":1393 + }, + { + "m27_0":0.715, + "m27_1":0.5077, + "m27_2":0.9994, + "m27_3":1075 + }, + { + "m27_0":0.914, + "m27_1":0.5494, + "m27_2":0.9998, + "m27_3":3688 + }, + { + "m27_0":0.3915, + "m27_1":0.5076, + "m27_2":0.9996, + "m27_3":1546 + }, + { + "m27_0":0.4136, + "m27_1":0.493, + "m27_2":0.9961, + "m27_3":166 + }, + { + "m27_0":0.451, + "m27_1":0.491, + "m27_2":0.9987, + "m27_3":505 + }, + { + "m27_0":0.6387, + "m27_1":0.5236, + "m27_2":0.9995, + "m27_3":1414 + }, + { + "m27_0":0.8408, + "m27_1":0.5469, + "m27_2":0.9998, + "m27_3":2968 + }, + { + "m27_0":0.3834, + "m27_1":0.4943, + "m27_2":0.9963, + "m27_3":175 + }, + { + "m27_0":0.8209, + "m27_1":0.5541, + "m27_2":0.9997, + "m27_3":1915 + }, + { + "m27_0":0.9102, + "m27_1":0.5561, + "m27_2":0.9998, + "m27_3":3136 + }, + { + "m27_0":0.7344, + "m27_1":0.5426, + "m27_2":0.9997, + "m27_3":2029 + }, + { + "m27_0":0.8998, + "m27_1":0.513, + "m27_2":0.9997, + "m27_3":2437 + }, + { + "m27_0":0.7967, + "m27_1":0.5634, + "m27_2":0.9997, + "m27_3":2359 + }, + { + "m27_0":0.7733, + "m27_1":0.5358, + "m27_2":0.9997, + "m27_3":1999 + }, + { + "m27_0":0.7442, + "m27_1":0.5383, + "m27_2":0.9997, + "m27_3":2416 + }, + { + "m27_0":0.7331, + "m27_1":0.5526, + "m27_2":0.9997, + "m27_3":2455 + }, + { + "m27_0":0.9303, + "m27_1":0.5434, + "m27_2":0.9998, + "m27_3":3190 + }, + { + "m27_0":0.7531, + "m27_1":0.5204, + "m27_2":0.9996, + "m27_3":1522 + }, + { + "m27_0":0.9199, + "m27_1":0.5463, + "m27_2":0.9998, + "m27_3":3298 + }, + { + "m27_0":0.5999, + "m27_1":0.5118, + "m27_2":0.9995, + "m27_3":1303 + }, + { + "m27_0":0.7868, + "m27_1":0.4871, + "m27_2":0.9992, + "m27_3":766 + }, + { + "m27_0":0.8046, + "m27_1":0.4926, + "m27_2":0.9996, + "m27_3":1726 + }, + { + "m27_0":0.5513, + "m27_1":0.5027, + "m27_2":0.9945, + "m27_3":118 + }, + { + "m27_0":0.7385, + "m27_1":0.4981, + "m27_2":0.9997, + "m27_3":2263 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.5912, + "m27_1":0.5119, + "m27_2":0.9996, + "m27_3":1624 + }, + { + "m27_0":0.7882, + "m27_1":0.5482, + "m27_2":0.9997, + "m27_3":2203 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.5287, + "m27_1":0.5583, + "m27_2":0.9997, + "m27_3":2101 + }, + { + "m27_0":0.4183, + "m27_1":0.4944, + "m27_2":0.9966, + "m27_3":193 + }, + { + "m27_0":0.9132, + "m27_1":0.5734, + "m27_2":0.9998, + "m27_3":3103 + }, + { + "m27_0":0.6221, + "m27_1":0.5369, + "m27_2":0.9996, + "m27_3":1657 + }, + { + "m27_0":0.7994, + "m27_1":0.5339, + "m27_2":0.9993, + "m27_3":994 + }, + { + "m27_0":0.5207, + "m27_1":0.4932, + "m27_2":0.9988, + "m27_3":535 + }, + { + "m27_0":0.7403, + "m27_1":0.5125, + "m27_2":0.9997, + "m27_3":2530 + }, + { + "m27_0":0.53, + "m27_1":0.5042, + "m27_2":0.9985, + "m27_3":436 + }, + { + "m27_0":0.691, + "m27_1":0.5335, + "m27_2":0.9995, + "m27_3":1228 + }, + { + "m27_0":0.6101, + "m27_1":0.5091, + "m27_2":0.9996, + "m27_3":1600 + }, + { + "m27_0":0.8786, + "m27_1":0.5452, + "m27_2":0.9998, + "m27_3":3376 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.904, + "m27_1":0.5402, + "m27_2":0.9998, + "m27_3":2908 + }, + { + "m27_0":0.899, + "m27_1":0.5475, + "m27_2":0.9997, + "m27_3":2482 + }, + { + "m27_0":0.9132, + "m27_1":0.5606, + "m27_2":0.9998, + "m27_3":3055 + }, + { + "m27_0":0.6065, + "m27_1":0.4972, + "m27_2":0.9995, + "m27_3":1201 + }, + { + "m27_0":0.8168, + "m27_1":0.5399, + "m27_2":0.9997, + "m27_3":2374 + }, + { + "m27_0":0.4924, + "m27_1":0.4881, + "m27_2":0.9989, + "m27_3":598 + }, + { + "m27_0":0.7439, + "m27_1":0.5165, + "m27_2":0.9997, + "m27_3":2602 + }, + { + "m27_0":0.8606, + "m27_1":0.5734, + "m27_2":0.9997, + "m27_3":2068 + }, + { + "m27_0":0.6604, + "m27_1":0.4898, + "m27_2":0.9992, + "m27_3":823 + }, + { + "m27_0":0.5287, + "m27_1":0.4875, + "m27_2":0.9973, + "m27_3":241 + }, + { + "m27_0":0.7155, + "m27_1":0.5235, + "m27_2":0.9994, + "m27_3":1138 + }, + { + "m27_0":0.3576, + "m27_1":0.4875, + "m27_2":0.9967, + "m27_3":196 + }, + { + "m27_0":0.3467, + "m27_1":0.4998, + "m27_2":0.9989, + "m27_3":598 + }, + { + "m27_0":0.5249, + "m27_1":0.4954, + "m27_2":0.9991, + "m27_3":703 + }, + { + "m27_0":0.4659, + "m27_1":0.5103, + "m27_2":0.9984, + "m27_3":403 + }, + { + "m27_0":0.7251, + "m27_1":0.5147, + "m27_2":0.9996, + "m27_3":1801 + }, + { + "m27_0":0.833, + "m27_1":0.5126, + "m27_2":0.9996, + "m27_3":1765 + }, + { + "m27_0":0.5252, + "m27_1":0.5377, + "m27_2":0.9988, + "m27_3":562 + }, + { + "m27_0":0.6789, + "m27_1":0.5114, + "m27_2":0.9995, + "m27_3":1300 + }, + { + "m27_0":0.7113, + "m27_1":0.5057, + "m27_2":0.9996, + "m27_3":1609 + }, + { + "m27_0":0.8473, + "m27_1":0.5576, + "m27_2":0.9997, + "m27_3":2200 + }, + { + "m27_0":0.8085, + "m27_1":0.5145, + "m27_2":0.9994, + "m27_3":1063 + }, + { + "m27_0":0.668, + "m27_1":0.5323, + "m27_2":0.9995, + "m27_3":1423 + }, + { + "m27_0":0.8701, + "m27_1":0.5691, + "m27_2":0.9997, + "m27_3":2344 + }, + { + "m27_0":0.6824, + "m27_1":0.5236, + "m27_2":0.9996, + "m27_3":1528 + }, + { + "m27_0":0.6839, + "m27_1":0.5376, + "m27_2":0.9997, + "m27_3":2227 + }, + { + "m27_0":0.4668, + "m27_1":0.5519, + "m27_2":0.9996, + "m27_3":1810 + }, + { + "m27_0":0.8883, + "m27_1":0.5422, + "m27_2":0.9997, + "m27_3":1924 + }, + { + "m27_0":0.8848, + "m27_1":0.5378, + "m27_2":0.9997, + "m27_3":2242 + }, + { + "m27_0":0.8293, + "m27_1":0.5453, + "m27_2":0.9997, + "m27_3":1879 + }, + { + "m27_0":0.742, + "m27_1":0.4801, + "m27_2":0.9997, + "m27_3":2008 + }, + { + "m27_0":0.8165, + "m27_1":0.4918, + "m27_2":0.9992, + "m27_3":799 + }, + { + "m27_0":0.8777, + "m27_1":0.5505, + "m27_2":0.9998, + "m27_3":3238 + }, + { + "m27_0":0.4947, + "m27_1":0.5057, + "m27_2":0.9994, + "m27_3":1135 + }, + { + "m27_0":0.7428, + "m27_1":0.5135, + "m27_2":0.9997, + "m27_3":2473 + }, + { + "m27_0":0.7956, + "m27_1":0.5463, + "m27_2":0.9995, + "m27_3":1396 + }, + { + "m27_0":0.8116, + "m27_1":0.5203, + "m27_2":0.9994, + "m27_3":1132 + }, + { + "m27_0":0.5649, + "m27_1":0.5149, + "m27_2":0.9995, + "m27_3":1291 + }, + { + "m27_0":0.8755, + "m27_1":0.535, + "m27_2":0.9997, + "m27_3":1909 + }, + { + "m27_0":0.7485, + "m27_1":0.5568, + "m27_2":0.9996, + "m27_3":1639 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.4199, + "m27_1":0.5007, + "m27_2":0.9984, + "m27_3":406 + }, + { + "m27_0":0.3764, + "m27_1":0.5002, + "m27_2":0.9989, + "m27_3":610 + }, + { + "m27_0":0.3333, + "m27_1":0.3889, + "m27_2":0.9594, + "m27_3":16 + }, + { + "m27_0":0.4395, + "m27_1":0.4773, + "m27_2":0.9981, + "m27_3":343 + }, + { + "m27_0":0.7974, + "m27_1":0.4958, + "m27_2":0.9996, + "m27_3":1540 + }, + { + "m27_0":0.8834, + "m27_1":0.5175, + "m27_2":0.9997, + "m27_3":1930 + }, + { + "m27_0":0.4051, + "m27_1":0.4754, + "m27_2":0.999, + "m27_3":622 + }, + { + "m27_0":0.8839, + "m27_1":0.5621, + "m27_2":0.9998, + "m27_3":2632 + }, + { + "m27_0":0.8339, + "m27_1":0.5309, + "m27_2":0.9997, + "m27_3":2209 + }, + { + "m27_0":0.6042, + "m27_1":0.5333, + "m27_2":0.9996, + "m27_3":1684 + }, + { + "m27_0":0.3436, + "m27_1":0.4916, + "m27_2":0.9961, + "m27_3":166 + }, + { + "m27_0":0.7376, + "m27_1":0.5064, + "m27_2":0.9996, + "m27_3":1594 + }, + { + "m27_0":0.4286, + "m27_1":0.4948, + "m27_2":0.9991, + "m27_3":739 + }, + { + "m27_0":0.7026, + "m27_1":0.5393, + "m27_2":0.9996, + "m27_3":1726 + }, + { + "m27_0":0.7732, + "m27_1":0.557, + "m27_2":0.9996, + "m27_3":1531 + }, + { + "m27_0":0.8132, + "m27_1":0.5132, + "m27_2":0.9994, + "m27_3":1039 + }, + { + "m27_0":0.6589, + "m27_1":0.4917, + "m27_2":0.9991, + "m27_3":712 + }, + { + "m27_0":0.8112, + "m27_1":0.5593, + "m27_2":0.9996, + "m27_3":1669 + }, + { + "m27_0":0.4405, + "m27_1":0.5107, + "m27_2":0.9983, + "m27_3":373 + }, + { + "m27_0":0.6893, + "m27_1":0.5283, + "m27_2":0.9997, + "m27_3":1963 + }, + { + "m27_0":0.8948, + "m27_1":0.5599, + "m27_2":0.9998, + "m27_3":3148 + }, + { + "m27_0":0.4922, + "m27_1":0.4813, + "m27_2":0.9989, + "m27_3":610 + }, + { + "m27_0":0.4148, + "m27_1":0.5312, + "m27_2":0.9991, + "m27_3":703 + }, + { + "m27_0":0.6857, + "m27_1":0.5434, + "m27_2":0.9992, + "m27_3":838 + }, + { + "m27_0":0.573, + "m27_1":0.5217, + "m27_2":0.9994, + "m27_3":1036 + }, + { + "m27_0":0.4862, + "m27_1":0.5091, + "m27_2":0.9981, + "m27_3":334 + }, + { + "m27_0":0.7837, + "m27_1":0.4969, + "m27_2":0.9996, + "m27_3":1609 + }, + { + "m27_0":0.7786, + "m27_1":0.5161, + "m27_2":0.9996, + "m27_3":1624 + }, + { + "m27_0":0.8428, + "m27_1":0.5477, + "m27_2":0.9998, + "m27_3":2743 + }, + { + "m27_0":0.9142, + "m27_1":0.5658, + "m27_2":0.9998, + "m27_3":3376 + }, + { + "m27_0":0.9109, + "m27_1":0.5735, + "m27_2":0.9998, + "m27_3":3013 + }, + { + "m27_0":0.3318, + "m27_1":0.4737, + "m27_2":0.9942, + "m27_3":112 + }, + { + "m27_0":0.8078, + "m27_1":0.5003, + "m27_2":0.9997, + "m27_3":1903 + }, + { + "m27_0":0.8347, + "m27_1":0.5154, + "m27_2":0.9997, + "m27_3":2149 + }, + { + "m27_0":0.5595, + "m27_1":0.4781, + "m27_2":0.9989, + "m27_3":607 + }, + { + "m27_0":0.9398, + "m27_1":0.5468, + "m27_2":0.9998, + "m27_3":3199 + }, + { + "m27_0":0.6859, + "m27_1":0.5018, + "m27_2":0.9996, + "m27_3":1666 + }, + { + "m27_0":0.7976, + "m27_1":0.5681, + "m27_2":0.9996, + "m27_3":1600 + }, + { + "m27_0":0.9093, + "m27_1":0.5616, + "m27_2":0.9998, + "m27_3":2611 + }, + { + "m27_0":0.93, + "m27_1":0.5543, + "m27_2":0.9998, + "m27_3":3298 + }, + { + "m27_0":0.3446, + "m27_1":0.5067, + "m27_2":0.9989, + "m27_3":595 + }, + { + "m27_0":0.4, + "m27_1":0.4845, + "m27_2":0.9963, + "m27_3":178 + }, + { + "m27_0":0.924, + "m27_1":0.5716, + "m27_2":0.9998, + "m27_3":3778 + }, + { + "m27_0":0.8206, + "m27_1":0.5559, + "m27_2":0.9998, + "m27_3":3043 + }, + { + "m27_0":0.907, + "m27_1":0.5334, + "m27_2":0.9998, + "m27_3":2611 + }, + { + "m27_0":0.4598, + "m27_1":0.497, + "m27_2":0.9987, + "m27_3":514 + }, + { + "m27_0":0.6526, + "m27_1":0.5155, + "m27_2":0.9996, + "m27_3":1579 + }, + { + "m27_0":0.6326, + "m27_1":0.5268, + "m27_2":0.999, + "m27_3":646 + } +] \ No newline at end of file diff --git a/frontend/src/components/Header.vue b/frontend/src/components/Header.vue index ca7173d..8554ab3 100644 --- a/frontend/src/components/Header.vue +++ b/frontend/src/components/Header.vue @@ -76,7 +76,7 @@
- Antti Oulasvirta, Samuli De Pascale, Janin Koch, Thomas Langerak, Jussi Jokinen, Kashyap Todi, Markku Laine, Manoj Kristhombuge, Yuxi Zhu, Aliaksei Miniukovich, Gregorio Palmas, Tino Weinkauf, Ai Nakajima, Valentin Ionita, Morteza Shiripour, Amir Hossein Kargaran, and Chuhan Jiao. + Antti Oulasvirta, Samuli De Pascale, Janin Koch, Thomas Langerak, Jussi Jokinen, Kashyap Todi, Markku Laine, Manoj Kristhombuge, Yuxi Zhu, Aliaksei Miniukovich, Gregorio Palmas, Tino Weinkauf, Ai Nakajima, Valentin Ionita, Morteza Shiripour, Amir Hossein Kargaran, Chuhan Jiao, and Nafiseh Nikeghbal.
diff --git a/metrics.json b/metrics.json index 2b219ce..9dfdaf5 100644 --- a/metrics.json +++ b/metrics.json @@ -1924,6 +1924,166 @@ "description": false } ] + }, + "m27": { + "id": "m27", + "name": "Quadtree decomposition", + "description": "Quadtree decomposition for 3 aesthetic dimensions including balance, symmetry, and equilibrium.", + "evidence": 3, + "relevance": 3, + "speed": 2, + "segmentation_required": false, + "references": [ + { + "title": "Ngo, D., Teo, L. and Byrne, J. (2003). Modelling interface aesthetics. Information Sciences 152, pp. 25-46. doi: https://doi.org/10.1016/S0020-0255(02)00404-8", + "url": "https://doi.org/10.1016/S0020-0255(02)00404-8" + }, + { + "title": "Zheng, X., Chakraborty, I., Lin, J. and Rauschenberger, R. (2009) Correlating Low-Level Image Statistics with Users' Rapid Aesthetic and Affective Judgments of Web Pages. In Proceedings of the SIGCHI Conference on Human Factors in Computing Systems (CHI'09 ~ Understanding Information), pp. 1-10. ACM. doi: https://doi.org/10.1145/1518701.1518703", + "url": "https://doi.org/10.1145/1518701.1518703" + }, + { + "title": "Reinecke, K., Yeh, T., Miratrix, L., Mardiko, R., Zhao, Y., Liu, J., and Gajos, K. Z. (2013) Predicting Users' First Impressions of Website Aesthetics With a Quantification of Perceived Visual Complexity and Colorfulness. In Proceedings of the SIGCHI Conference on Human Factors in Computing Systems (CHI'13), pp. 2049-2058, ACM. doi: https://doi.org/10.1145/2470654.2481281", + "url": "https://doi.org/10.1145/2470654.2481281" + } + ], + "results": [ + { + "id": "m27_0", + "index": 0, + "type": "float", + "name": "Balance", + "description": false, + "scores": [ + { + "id": "r1", + "range": [0.0, 0.5871], + "description": "Unbalanced", + "icon": ["fas", "exclamation-triangle"], + "judgment": "bad" + }, + { + "id": "r2", + "range": [0.5872, 0.8425], + "description": "Fair", + "icon": [null, null], + "judgment": "normal" + }, + { + "id": "r3", + "range": [0.8426, 1.0], + "description": "Balanced", + "icon": ["far", "check-circle"], + "judgment": "good" + } + ] + }, + { + "id": "m27_1", + "index": 1, + "type": "float", + "name": "Symmetry", + "description": false, + "scores": [ + { + "id": "r1", + "range": [0.0, 0.5006], + "description": "Non-Symmetric", + "icon": ["fas", "exclamation-triangle"], + "judgment": "bad" + }, + { + "id": "r2", + "range": [0.5007, 0.5429], + "description": "Fair", + "icon": [null, null], + "judgment": "normal" + }, + { + "id": "r3", + "range": [0.5430, 1.0], + "description": "Symmetric", + "icon": ["far", "check-circle"], + "judgment": "good" + } + ] + }, + { + "id": "m27_2", + "index": 2, + "type": "float", + "name": "Equilibrium", + "description": false, + "scores": [ + { + "id": "r1", + "range": [0.0, 0.9994], + "description": "Not centralized", + "icon": ["fas", "exclamation-triangle"], + "judgment": "bad" + }, + { + "id": "r2", + "range": [0.9995, 0.9996], + "description": "Fair", + "icon": [null, null], + "judgment": "normal" + }, + { + "id": "r3", + "range": [0.9997, 1.0], + "description": "Centralized", + "icon": ["far", "check-circle"], + "judgment": "good" + } + ] + }, + { + "id": "m27_3", + "index": 3, + "type": "int", + "name": "Number of leaves", + "description": false, + "scores": [ + { + "id": "r1", + "range": [0, 1061], + "description": "Low visual complexity", + "icon": ["far", "check-circle"], + "judgment": "good" + }, + { + "id": "r2", + "range": [1062, 2347], + "description": "Fair visual complexity", + "icon": [null, null], + "judgment": "normal" + }, + + { + "id": "r1", + "range": [2348, null], + "description": "High visual complexity", + "icon": ["fas", "exclamation-triangle"], + "judgment": "bad" + } + ] + }, + { + "id": "m27_4", + "index": 4, + "type": "b64", + "name": "Quadtree blocks - color entropy based", + "description": "Quadtree blocks of the image based on the shannon entropy comparison over colored image." + }, + { + "id": "m27_5", + "index": 5, + "type": "b64", + "name": "Quadtree blocks - gray std based", + "description": "Quadtree blocks of the image based on standard deviation comparison over grayscale image." + } + ] } } }