From d21160d6f8c237d8169966015a6a7413c614259d Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Wed, 21 Jun 2023 15:12:58 +0200 Subject: [PATCH 01/29] changed summmary.py logic --- ammico/display.py | 4 +- ammico/summary.py | 140 +++++++++++++++++++++++++++++++++++++----- ammico/testing_all.py | 27 ++++++-- 3 files changed, 149 insertions(+), 22 deletions(-) mode change 100644 => 100755 ammico/testing_all.py diff --git a/ammico/display.py b/ammico/display.py index f8c594f3..a33a9a1c 100644 --- a/ammico/display.py +++ b/ammico/display.py @@ -197,7 +197,9 @@ def update_picture(self, img_path: str): else: return None - def _right_output_analysis(self, all_options: dict, current_value: str) -> dict: + def _right_output_analysis( + self, image, all_options: dict, current_value: str + ) -> dict: """Callback function to perform analysis on the selected image and return the output. Args: diff --git a/ammico/summary.py b/ammico/summary.py index 50fc2ee5..20a4ffbe 100644 --- a/ammico/summary.py +++ b/ammico/summary.py @@ -5,9 +5,64 @@ class SummaryDetector(AnalysisMethod): - def __init__(self, subdict: dict) -> None: + def __init__( + self, + subdict: dict = {}, + summary_model_type: str = "base", + analysis_type: str = "summary_and_questions", + list_of_questions: list = [ + "Are there people in the image?", + "What is this picture about?", + ], + summary_model=None, + summary_vis_processors=None, + summary_vqa_model=None, + summary_vqa_vis_processors=None, + summary_vqa_txt_processors=None, + ) -> None: + """ + SummaryDetector class for analysing images using the blip_caption model. + + Args: + subdict (dict, optional): Dictionary containing the image to be analysed. Defaults to {}. + summary_model_type (str, optional): Type of blip_caption model to use. Defaults to "base". + analysis_type (str, optional): Type of analysis to perform. Defaults to "analyse_summary_and_questions". + list_of_questions (list, optional): List of questions to answer. Defaults to ["Are there people in the image?", "What is this picture about?"]. + summary_model ([type], optional): blip_caption model. Defaults to None. + summary_vis_processors ([type], optional): Preprocessors for visual inputs. Defaults to None. + """ + super().__init__(subdict) self.summary_device = "cuda" if cuda.is_available() else "cpu" + self.summary_model_type = summary_model_type + self.analysis_type = analysis_type + self.list_of_questions = list_of_questions + if ( + (summary_model is None) + and (summary_vis_processors is None) + and (analysis_type != "questions") + ): + self.summary_model, self.summary_vis_processors = self.load_model( + model_type=summary_model_type + ) + else: + self.summary_model = summary_model + self.summary_vis_processors = summary_vis_processors + if ( + (summary_vqa_model is None) + and (summary_vqa_vis_processors is None) + and (summary_vqa_txt_processors is None) + and (analysis_type != "summary") + ): + ( + self.summary_vqa_model, + self.summary_vqa_vis_processors, + self.summary_vqa_txt_processors, + ) = self.load_vqa_model() + else: + self.summary_vqa_model = summary_vqa_model + self.summary_vqa_vis_processors = summary_vqa_vis_processors + self.summary_vqa_txt_processors = summary_vqa_txt_processors def load_model_base(self): """ @@ -63,7 +118,51 @@ def load_model(self, model_type: str): summary_model, summary_vis_processors = select_model[model_type](self) return summary_model, summary_vis_processors - def analyse_image(self, summary_model=None, summary_vis_processors=None): + def load_vqa_model(self): + """ + Load blip_vqa model and preprocessors for visual and text inputs from lavis.models. + + Args: + + Returns: + model (torch.nn.Module): model. + vis_processors (dict): preprocessors for visual inputs. + txt_processors (dict): preprocessors for text inputs. + + """ + ( + summary_vqa_model, + summary_vqa_vis_processors, + summary_vqa_txt_processors, + ) = load_model_and_preprocess( + name="blip_vqa", + model_type="vqav2", + is_eval=True, + device=self.summary_device, + ) + return summary_vqa_model, summary_vqa_vis_processors, summary_vqa_txt_processors + + def analyse_image(self): + """ + Analyse image with blip_caption model. + + Args: + analysis_type (str): type of the analysis. + + Returns: + self.subdict (dict): dictionary with analysis results. + """ + if self.analysis_type == "summary_and_questions": + self.analyse_summary() + self.analyse_questions(self.list_of_questions) + elif self.analysis_type == "summary": + self.analyse_summary() + elif self.analysis_type == "questions": + self.analyse_questions(self.list_of_questions) + + return self.subdict + + def analyse_summary(self): """ Create 1 constant and 3 non deterministic captions for image. @@ -74,21 +173,19 @@ def analyse_image(self, summary_model=None, summary_vis_processors=None): Returns: self.subdict (dict): dictionary with constant image summary and 3 non deterministic summary. """ - if summary_model is None and summary_vis_processors is None: - summary_model, summary_vis_processors = self.load_model_base() path = self.subdict["filename"] raw_image = Image.open(path).convert("RGB") image = ( - summary_vis_processors["eval"](raw_image) + self.summary_vis_processors["eval"](raw_image) .unsqueeze(0) .to(self.summary_device) ) with no_grad(): - self.subdict["const_image_summary"] = summary_model.generate( + self.subdict["const_image_summary"] = self.summary_model.generate( {"image": image} )[0] - self.subdict["3_non-deterministic summary"] = summary_model.generate( + self.subdict["3_non-deterministic summary"] = self.summary_model.generate( {"image": image}, use_nucleus_sampling=True, num_captions=3 ) return self.subdict @@ -103,16 +200,25 @@ def analyse_questions(self, list_of_questions: list[str]) -> dict: Returns: self.subdict (dict): dictionary with answers to questions. """ - ( - summary_vqa_model, - summary_vqa_vis_processors, - summary_vqa_txt_processors, - ) = load_model_and_preprocess( - name="blip_vqa", - model_type="vqav2", - is_eval=True, - device=self.summary_device, - ) + if ( + (self.summary_vqa_model is None) + and (self.summary_vqa_vis_processors is None) + and (self.summary_vqa_txt_processors is None) + ): + ( + summary_vqa_model, + summary_vqa_vis_processors, + summary_vqa_txt_processors, + ) = load_model_and_preprocess( + name="blip_vqa", + model_type="vqav2", + is_eval=True, + device=self.summary_device, + ) + else: + summary_vqa_model = self.summary_vqa_model + summary_vqa_vis_processors = self.summary_vqa_vis_processors + summary_vqa_txt_processors = self.summary_vqa_txt_processors if len(list_of_questions) > 0: path = self.subdict["filename"] raw_image = Image.open(path).convert("RGB") diff --git a/ammico/testing_all.py b/ammico/testing_all.py old mode 100644 new mode 100755 index 197fa6e3..57ae6583 --- a/ammico/testing_all.py +++ b/ammico/testing_all.py @@ -1,13 +1,32 @@ import ammico if __name__ == "__main__": - images = ammico.find_files(path=".") + images = ammico.find_files( + path="../data/test/facebook_screenshots/", pattern="*.jpg" + ) mydict = ammico.initialize_dict(images) + obj = ammico.SummaryDetector() + summary_m, summary_v = obj.load_model("base") + ( + summary_vqa_model, + summary_vqa_vis_processors, + summary_vqa_txt_processors, + ) = obj.load_vqa_model() for key in mydict: - mydict[key] = ammico.TextDetector( - mydict[key], analyse_text=True + mydict[key] = ammico.SummaryDetector( + mydict[key], + analysis_type="summary_and_questions", + summary_model=summary_m, + summary_vis_processors=summary_v, + summary_vqa_model=summary_vqa_model, + summary_vqa_vis_processors=summary_vqa_vis_processors, + summary_vqa_txt_processors=summary_vqa_txt_processors, ).analyse_image() print(mydict) outdict = ammico.append_data_to_dict(mydict) df = ammico.dump_df(outdict) - df.to_csv("data_out.csv") + df.to_csv("data_out4.csv") +# ammico.TextDetector +# ammico.EmotionDetector +# ammico.ObjectDetector +# ammico.SummaryDetector From a3b799e1f868a19fd6fe39028635b017af2ab51e Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Wed, 21 Jun 2023 15:22:00 +0200 Subject: [PATCH 02/29] fixing test_summary --- ammico/test/test_summary.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ammico/test/test_summary.py b/ammico/test/test_summary.py index 909c977f..f63f7773 100644 --- a/ammico/test/test_summary.py +++ b/ammico/test/test_summary.py @@ -63,9 +63,12 @@ def test_analyse_image(get_dict): ) # run two different images for key in get_dict.keys(): - get_dict[key] = sm.SummaryDetector(get_dict[key]).analyse_image( - summary_model, summary_vis_processors - ) + get_dict[key] = sm.SummaryDetector( + get_dict[key], + analysis_type="summary", + summary_model=summary_model, + summary_vis_processors=summary_vis_processors, + ).analyse_image() assert len(get_dict) == 2 for key in get_dict.keys(): assert len(get_dict[key]["3_non-deterministic summary"]) == 3 @@ -84,9 +87,11 @@ def test_analyse_questions(get_dict): "What happends on the picture?", ] for key in get_dict: - get_dict[key] = sm.SummaryDetector(get_dict[key]).analyse_questions( - list_of_questions - ) + get_dict[key] = sm.SummaryDetector( + get_dict[key], + analysis_type="questions", + list_of_questions=list_of_questions, + ).analyse_image() assert len(get_dict) == 2 list_of_questions_ans = ["2", "100"] list_of_questions_ans2 = ["flood", "festival"] From aa6ed41c487730f6db5c45c1cee47fe20b35a756 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Wed, 21 Jun 2023 15:25:53 +0200 Subject: [PATCH 03/29] added macos for testing --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78aa0ab0..a84e6540 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: python -m pip install --upgrade pip python -m pip install -e . - name: Run pytest linux (linux-only) - if: matrix.os == 'ubuntu-22.04' + if: matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-latest' run: | cd ammico python -m pytest -m "not gcv and not long" -svv --cov=. --cov-report=xml From f2fee741e0051402d6b946bd1bd31b2d7d168914 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Wed, 21 Jun 2023 15:42:11 +0200 Subject: [PATCH 04/29] fixed_display_test --- ammico/test/test_display.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ammico/test/test_display.py b/ammico/test/test_display.py index 4d3c1f15..a0b3792e 100644 --- a/ammico/test/test_display.py +++ b/ammico/test/test_display.py @@ -49,8 +49,8 @@ def test_AnalysisExplorer(get_path): assert analysis_explorer_objects.update_picture(None) is None - analysis_explorer_faces._right_output_analysis(all_options_dict, path_img_1) - analysis_explorer_objects._right_output_analysis(all_options_dict, path_img_2) + analysis_explorer_faces._right_output_analysis(1, all_options_dict, path_img_1) + analysis_explorer_objects._right_output_analysis(1, all_options_dict, path_img_2) with pytest.raises(EnvironmentError): analysis_explorer_faces.run_server(port=8050) From 8ab9139749793dedf8f755d85fb306cc58d1987c Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Thu, 22 Jun 2023 13:44:47 +0200 Subject: [PATCH 05/29] fixed docs and exceptions --- ammico/summary.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ammico/summary.py b/ammico/summary.py index 20a4ffbe..fe480e40 100644 --- a/ammico/summary.py +++ b/ammico/summary.py @@ -25,11 +25,20 @@ def __init__( Args: subdict (dict, optional): Dictionary containing the image to be analysed. Defaults to {}. - summary_model_type (str, optional): Type of blip_caption model to use. Defaults to "base". - analysis_type (str, optional): Type of analysis to perform. Defaults to "analyse_summary_and_questions". + summary_model_type (str, optional): Type of blip_caption model to use. Can be "base" or "large". Defaults to "base". + analysis_type (str, optional): Type of analysis to perform. Can be "summary", "questions" or "summary_and_questions". Defaults to "summary_and_questions". list_of_questions (list, optional): List of questions to answer. Defaults to ["Are there people in the image?", "What is this picture about?"]. summary_model ([type], optional): blip_caption model. Defaults to None. summary_vis_processors ([type], optional): Preprocessors for visual inputs. Defaults to None. + summary_vqa_model ([type], optional): blip_vqa model. Defaults to None. + summary_vqa_vis_processors ([type], optional): Preprocessors for vqa visual inputs. Defaults to None. + summary_vqa_txt_processors ([type], optional): Preprocessors for vqa text inputs. Defaults to None. + + Raises: + ValueError: If analysis_type is not one of "summary", "questions" or "summary_and_questions". + + Returns: + None. """ super().__init__(subdict) @@ -37,6 +46,10 @@ def __init__( self.summary_model_type = summary_model_type self.analysis_type = analysis_type self.list_of_questions = list_of_questions + if analysis_type not in ["summary", "questions", "summary_and_questions"]: + raise ValueError( + "analysis_type must be one of 'summary', 'questions' or 'summary_and_questions'" + ) if ( (summary_model is None) and (summary_vis_processors is None) @@ -147,7 +160,6 @@ def analyse_image(self): Analyse image with blip_caption model. Args: - analysis_type (str): type of the analysis. Returns: self.subdict (dict): dictionary with analysis results. @@ -167,11 +179,9 @@ def analyse_summary(self): Create 1 constant and 3 non deterministic captions for image. Args: - summary_model (str): model. - summary_vis_processors (str): preprocessors for visual inputs. Returns: - self.subdict (dict): dictionary with constant image summary and 3 non deterministic summary. + self.subdict (dict): dictionary with analysis results. """ path = self.subdict["filename"] From 5bdf325958d1c36e0f3699f18e443b4eff106af2 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Thu, 22 Jun 2023 14:00:52 +0200 Subject: [PATCH 06/29] fixed code smells --- ammico/summary.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ammico/summary.py b/ammico/summary.py index fe480e40..e0117ad0 100644 --- a/ammico/summary.py +++ b/ammico/summary.py @@ -10,10 +10,7 @@ def __init__( subdict: dict = {}, summary_model_type: str = "base", analysis_type: str = "summary_and_questions", - list_of_questions: list = [ - "Are there people in the image?", - "What is this picture about?", - ], + list_of_questions: str = None, summary_model=None, summary_vis_processors=None, summary_vqa_model=None, @@ -45,7 +42,13 @@ def __init__( self.summary_device = "cuda" if cuda.is_available() else "cpu" self.summary_model_type = summary_model_type self.analysis_type = analysis_type - self.list_of_questions = list_of_questions + if list_of_questions is None: + list_of_questions = [ + "Are there people in the image?", + "What is this picture about?", + ] + else: + self.list_of_questions = list_of_questions if analysis_type not in ["summary", "questions", "summary_and_questions"]: raise ValueError( "analysis_type must be one of 'summary', 'questions' or 'summary_and_questions'" From 0beb9c5a3fac63ccfc180bc570a3359e8d0f6528 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Thu, 22 Jun 2023 14:08:05 +0200 Subject: [PATCH 07/29] main merge --- README.md | 22 ++- ammico/colors.py | 118 +++++++++++++ ammico/data/Color_tables.csv | 24 +++ ammico/display.py | 4 +- ammico/notebooks/colors_analysis.ipynb | 195 +++++++++++++++++++++ ammico/notebooks/colors_expression.ipynb | 152 ---------------- ammico/test/test_colors.py | 55 ++++++ ammico/utils.py | 16 +- docs/source/ammico.rst | 8 + docs/source/index.rst | 1 + docs/source/notebooks/Example colors.ipynb | 195 +++++++++++++++++++++ pyproject.toml | 17 +- 12 files changed, 644 insertions(+), 163 deletions(-) create mode 100644 ammico/colors.py create mode 100644 ammico/data/Color_tables.csv create mode 100644 ammico/notebooks/colors_analysis.ipynb delete mode 100644 ammico/notebooks/colors_expression.ipynb create mode 100644 ammico/test/test_colors.py create mode 100644 docs/source/notebooks/Example colors.ipynb diff --git a/README.md b/README.md index 27697141..4cf2c9b9 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Use pre-processed image files such as social media posts with comments and proce The `AMMICO` package can be installed using pip: ``` -pip install git+https://github.com/ssciwr/ammico.git +pip install ammico ``` This will install the package and its dependencies locally. @@ -45,19 +45,21 @@ This will install the package and its dependencies locally. There are sample notebooks in the `notebooks` folder for you to explore the package: 1. Text extraction: Use the notebook `get-text-from-image.ipynb` to extract any text from the images. The text is directly translated into English. If the text should be further analysed, set the keyword `analyse_text` to `True` as demonstrated in the notebook.\ -**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/notebooks/get-text-from-image.ipynb)** +**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/ammico/notebooks/get-text-from-image.ipynb)** Place the data files and google cloud vision API key in your google drive to access the data. 1. Emotion recognition: Use the notebook `facial_expressions.ipynb` to identify if there are faces on the image, if they are wearing masks, and if they are not wearing masks also the race, gender and dominant emotion. -**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/notebooks/facial_expressions.ipynb)** +**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/ammico/notebooks/facial_expressions.ipynb)** Place the data files in your google drive to access the data. 1. Content extraction: Use the notebook `image_summary.ipynb` to create captions for the images and ask questions about the image content. -**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/notebooks/image_summary.ipynb)** +**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/ammico/notebooks/image_summary.ipynb)** 1. Multimodal content: Use the notebook `multimodal_search.ipynb` to find the best fitting images to an image or text query. -**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/notebooks/multimodal_search.ipynb)** +**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/ammico/notebooks/multimodal_search.ipynb)** +1. Color analysis: Use the notebook `color_analysis.ipynb` to identify colors the image. The colors are then classified into the main named colors in the English language. +**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/ammico/notebooks/colors_analysis.ipynb)** 1. Object analysis: Use the notebook `ojects_expression.ipynb` to identify certain objects in the image. Currently, the following objects are being identified: person, bicycle, car, motorcycle, airplane, bus, train, truck, boat, traffic light, cell phone. -**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/notebooks/objects_expression.ipynb)** - -There are further notebooks that are currently of exploratory nature (`colors_expression.ipynb` to identify certain colors on the image). To crop social media posts use the `cropposts.ipynb` notebook. +**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/ammico/notebooks/objects_expression.ipynb)** +1. To crop social media posts use the `cropposts.ipynb` notebook. +**You can run this notebook on google colab: [Here](https://colab.research.google.com/github/ssciwr/ammico/blob/main/ammico/notebooks/cropposts.ipynb)** ## Features ### Text extraction @@ -86,6 +88,10 @@ Emotion recognition is carried out using the [deepface](https://github.com/seren Object detection is carried out using [cvlib](https://github.com/arunponnusamy/cvlib) and the [YOLOv4](https://github.com/AlexeyAB/darknet) model. This library detects faces, people, and several inanimate objects; we currently have restricted the output to person, bicycle, car, motorcycle, airplane, bus, train, truck, boat, traffic light, cell phone. +### Color/hue detection + +Color detection is carried out using [colorgram.py](https://github.com/obskyr/colorgram.py) and [colour](https://github.com/vaab/colour) for the distance metric. The colors can be classified into the main named colors/hues in the English language, that are red, green, blue, yellow, cyan, orange, purple, pink, brown, grey, white, black. + ### Cropping of posts Social media posts can automatically be cropped to remove further comments on the page and restrict the textual content to the first comment only. \ No newline at end of file diff --git a/ammico/colors.py b/ammico/colors.py new file mode 100644 index 00000000..21bb3b2c --- /dev/null +++ b/ammico/colors.py @@ -0,0 +1,118 @@ +import numpy as np +import webcolors +import pandas as pd +from collections import defaultdict +import colorgram +import colour +from ammico.utils import get_color_table, AnalysisMethod + + +class ColorDetector(AnalysisMethod): + def __init__( + self, + subdict: dict, + delta_e_method: str = "CIE 1976", + ) -> None: + """Color Analysis class, analyse hue and identify named colors. + + Args: + subdict (dict): The dictionary containing the image path. + delta_e_method (str): The calculation method used for assigning the + closest color name, defaults to "CIE 1976". + """ + super().__init__(subdict) + self.subdict.update(self.set_keys()) + self.merge_color = True + self.n_colors = 100 + self.delta_e_method = delta_e_method + + def set_keys(self) -> dict: + colors = { + "red": 0, + "green": 0, + "blue": 0, + "yellow": 0, + "cyan": 0, + "orange": 0, + "purple": 0, + "pink": 0, + "brown": 0, + "grey": 0, + "white": 0, + "black": 0, + } + return colors + + def analyse_image(self): + """ + Uses the colorgram library to extract the n most common colors from the images. + One problem is, that the most common colors are taken before beeing categorized, + so for small values it might occur that the ten most common colors are shades of grey, + while other colors are present but will be ignored. Because of this n_colors=100 was chosen as default. + + The colors are then matched to the closest color in the CSS3 color list using the delta-e metric. + They are then merged into one data frame. + The colors can be reduced to a smaller list of colors using the get_color_table function. + These colors are: "red", "green", "blue", "yellow","cyan", "orange", "purple", "pink", "brown", "grey", "white", "black". + + Returns: + dict: Dictionary with color names as keys and percentage of color in image as values. + """ + filename = self.subdict["filename"] + + colors = colorgram.extract(filename, self.n_colors) + for color in colors: + rgb_name = self.rgb2name( + color.rgb, + merge_color=self.merge_color, + delta_e_method=self.delta_e_method, + ) + self.subdict[rgb_name] += round(color.proportion, 2) + + return self.subdict + + def rgb2name( + self, c, merge_color: bool = True, delta_e_method: str = "CIE 1976" + ) -> str: + """Take an rgb color as input and return the closest color name from the CSS3 color list. + + Args: + c (Union[List,tuple]): RGB value. + merge_color (bool, Optional): Whether color name should be reduced, defaults to True. + Returns: + str: Closest matching color name. + """ + if len(c) != 3: + raise ValueError("Input color must be a list or tuple of length 3 (RGB).") + + h_color = "#{:02x}{:02x}{:02x}".format(int(c[0]), int(c[1]), int(c[2])) + try: + output_color = webcolors.hex_to_name(h_color, spec="css3") + output_color = output_color.lower().replace("grey", "gray") + except ValueError: + delta_e_lst = [] + filtered_colors = webcolors.CSS3_NAMES_TO_HEX + + for _, img_hex in filtered_colors.items(): + cur_clr = webcolors.hex_to_rgb(img_hex) + # calculate color Delta-E + delta_e = colour.delta_E(c, cur_clr, method=delta_e_method) + delta_e_lst.append(delta_e) + # find lowest delta-e + min_diff = np.argsort(delta_e_lst)[0] + output_color = ( + str(list(filtered_colors.items())[min_diff][0]) + .lower() + .replace("grey", "gray") + ) + + # match color to reduced list: + if merge_color: + for reduced_key, reduced_color_sub_list in get_color_table().items(): + if str(output_color).lower() in [ + str(color_name).lower() + for color_name in reduced_color_sub_list["ColorName"] + ]: + output_color = reduced_key.lower() + break + return output_color diff --git a/ammico/data/Color_tables.csv b/ammico/data/Color_tables.csv new file mode 100644 index 00000000..7fad000e --- /dev/null +++ b/ammico/data/Color_tables.csv @@ -0,0 +1,24 @@ +Pink;Pink;purple;purple;red;red;orange;orange;yellow;yellow;green;green;cyan;cyan;blue;blue;brown;brown;white;white;grey;grey;black;black +ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX;ColorName;HEX +Pink;#FFC0CB;Lavender;#E6E6FA;LightSalmon;#FFA07A;Orange;#FFA500;Gold;#FFD700;GreenYellow;#ADFF2F;Aqua;#00FFFF;CadetBlue;#5F9EA0;Cornsilk;#FFF8DC;White;#FFFFFF;Gainsboro;#DCDCDC;Black;#000000 +LightPink;#FFB6C1;Thistle;#D8BFD8;Salmon;#FA8072;DarkOrange;#FF8C00;Yellow;#FFFF00;Chartreuse;#7FFF00;Cyan;#00FFFF;SteelBlue;#4682B4;BlanchedAlmond;#FFEBCD;Snow;#FFFAFA;LightGray;#D3D3D3;; +HotPink;#FF69B4;Plum;#DDA0DD;DarkSalmon;#E9967A;Coral;#FF7F50;LightYellow;#FFFFE0;LawnGreen;#7CFC00;LightCyan;#E0FFFF;LightSteelBlue;#B0C4DE;Bisque;#FFE4C4;HoneyDew;#F0FFF0;Silver;#C0C0C0;; +DeepPink;#FF1493;Orchid;#DA70D6;LightCoral;#F08080;Tomato;#FF6347;LemonChiffon;#FFFACD;Lime;#00FF00;PaleTurquoise;#AFEEEE;LightBlue;#ADD8E6;NavajoWhite;#FFDEAD;MintCream;#F5FFFA;DarkGray;#A9A9A9;; +PaleVioletRed;#DB7093;Violet;#EE82EE;IndianRed;#CD5C5C;OrangeRed;#FF4500;LightGoldenRodYellow;#FAFAD2;LimeGreen;#32CD32;Aquamarine;#7FFFD4;PowderBlue;#B0E0E6;Wheat;#F5DEB3;Azure;#F0FFFF;DimGray;#696969;; +MediumVioletRed;#C71585;Fuchsia;#FF00FF;Crimson;#DC143C;;;PapayaWhip;#FFEFD5;PaleGreen;#98FB98;Turquoise;#40E0D0;LightSkyBlue;#87CEFA;BurlyWood;#DEB887;AliceBlue;#F0F8FF;Gray;#808080;; +;;Magenta;#FF00FF;Red;#FF0000;;;Moccasin;#FFE4B5;LightGreen;#90EE90;MediumTurquoise;#48D1CC;SkyBlue;#87CEEB;Tan;#D2B48C;GhostWhite;#F8F8FF;LightSlateGray;#778899;; +;;MediumOrchid;#BA55D3;FireBrick;#B22222;;;PeachPuff;#FFDAB9;MediumSpringGreen;#00FA9A;DarkTurquoise;#00CED1;CornflowerBlue;#6495ED;RosyBrown;#BC8F8F;WhiteSmoke;#F5F5F5;SlateGray;#708090;; +;;DarkOrchid;#9932CC;DarkRed;#8B0000;;;PaleGoldenRod;#EEE8AA;SpringGreen;#00FF7F;;;DeepSkyBlue;#00BFFF;SandyBrown;#F4A460;SeaShell;#FFF5EE;DarkSlateGray;#2F4F4F;; +;;DarkViolet;#9400D3;;;;;Khaki;#F0E68C;MediumSeaGreen;#3CB371;;;DodgerBlue;#1E90FF;GoldenRod;#DAA520;Beige;#F5F5DC;;;; +;;BlueViolet;#8A2BE2;;;;;DarkKhaki;#BDB76B;SeaGreen;#2E8B57;;;RoyalBlue;#4169E1;DarkGoldenRod;#B8860B;OldLace;#FDF5E6;;;; +;;DarkMagenta;#8B008B;;;;;;;ForestGreen;#228B22;;;Blue;#0000FF;Peru;#CD853F;FloralWhite;#FFFAF0;;;; +;;Purple;#800080;;;;;;;Green;#008000;;;MediumBlue;#0000CD;Chocolate;#D2691E;Ivory;#FFFFF0;;;; +;;MediumPurple;#9370DB;;;;;;;DarkGreen;#006400;;;DarkBlue;#00008B;Olive;#808000;AntiqueWhite;#FAEBD7;;;; +;;MediumSlateBlue;#7B68EE;;;;;;;YellowGreen;#9ACD32;;;Navy;#000080;SaddleBrown;#8B4513;Linen;#FAF0E6;;;; +;;SlateBlue;#6A5ACD;;;;;;;OliveDrab;#6B8E23;;;MidnightBlue;#191970;Sienna;#A0522D;LavenderBlush;#FFF0F5;;;; +;;DarkSlateBlue;#483D8B;;;;;;;DarkOliveGreen;#556B2F;;;;;Brown;#A52A2A;MistyRose;#FFE4E1;;;; +;;RebeccaPurple;#663399;;;;;;;MediumAquaMarine;#66CDAA;;;;;Maroon;#800000;;;;;; +;;Indigo;#4B0082;;;;;;;DarkSeaGreen;#8FBC8F;;;;;;;;;;;; +;;;;;;;;;;LightSeaGreen;#20B2AA;;;;;;;;;;;; +;;;;;;;;;;DarkCyan;#008B8B;;;;;;;;;;;; +;;;;;;;;;;Teal;#008080;;;;;;;;;;;; diff --git a/ammico/display.py b/ammico/display.py index a33a9a1c..2d449b33 100644 --- a/ammico/display.py +++ b/ammico/display.py @@ -1,6 +1,7 @@ import ammico.faces as faces import ammico.text as text import ammico.objects as objects +import ammico.colors as colors from ammico.utils import is_interactive import ammico.summary as summary import dash_renderjson @@ -45,7 +46,7 @@ def __init__(self, mydict: dict, identify: str = "faces") -> None: "base0F": "#cc6633", } - # Setup the layout + # Setup the layout app_layout = html.Div( [ # Top @@ -214,6 +215,7 @@ def _right_output_analysis( "text-on-image": text.TextDetector, "objects": objects.ObjectDetector, "summary": summary.SummaryDetector, + "colors": colors.ColorDetector, } # Get image ID from dropdown value, which is the filepath diff --git a/ammico/notebooks/colors_analysis.ipynb b/ammico/notebooks/colors_analysis.ipynb new file mode 100644 index 00000000..d7f0bdea --- /dev/null +++ b/ammico/notebooks/colors_analysis.ipynb @@ -0,0 +1,195 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Color analysis of pictures\n", + "\n", + "\n", + "\n", + "This notebook shows primary color analysis of color image using K-Means algorithm.\n", + "The output are N primary colors and their corresponding percentage.\n", + "\n", + "The first cell is only run on google colab and installs the [ammico](https://github.com/ssciwr/AMMICO) package.\n", + "\n", + "After that, we can import `ammico` and read in the files given a folder path." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# if running on google colab\n", + "# flake8-noqa-cell\n", + "import os\n", + "\n", + "if \"google.colab\" in str(get_ipython()):\n", + " # update python version\n", + " # install setuptools\n", + " # %pip install setuptools==61 -qqq\n", + " # install ammico\n", + " %pip install git+https://github.com/ssciwr/ammico.git -qqq\n", + " # mount google drive for data and API key\n", + " from google.colab import drive\n", + "\n", + " drive.mount(\"/content/drive\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import ammico\n", + "from ammico import utils as mutils\n", + "from ammico import display as mdisplay\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We select a subset of image files to try the color analysis on, see the `limit` keyword. The `find_files` function finds image files within a given directory:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Here you need to provide the path to your google drive folder\n", + "# or local folder containing the images\n", + "images = mutils.find_files(\n", + " path=\"/content/drive/MyDrive/misinformation-data/\",\n", + " limit=10,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need to initialize the main dictionary that contains all information for the images and is updated through each subsequent analysis:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mydict = mutils.initialize_dict(images)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To check the analysis, you can inspect the analyzed elements here. Loading the results takes a moment, so please be patient. If you are sure of what you are doing, you can skip this and directly export a csv file in the step below.\n", + "Here, we display the color detection results provided by `colorgram` and `colour` libraries. Click on the tabs to see the results in the right sidebar. You may need to increment the `port` number if you are already running several notebook instances on the same server." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "analysis_explorer = mdisplay.AnalysisExplorer(mydict, identify=\"colors\")\n", + "analysis_explorer.run_server(port = 8057)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instead of inspecting each of the images, you can also directly carry out the analysis and export the result into a csv. This may take a while depending on how many images you have loaded." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for key in mydict.keys():\n", + " mydict[key] = ammico.colors.ColorDetector(mydict[key]).analyse_image()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These steps are required to convert the dictionary of dictionarys into a dictionary with lists, that can be converted into a pandas dataframe and exported to a csv file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "outdict = mutils.append_data_to_dict(mydict)\n", + "df = mutils.dump_df(outdict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check the dataframe:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.head(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Write the csv file - here you should provide a file path and file name for the csv file to be written." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.to_csv(\"/content/drive/MyDrive/misinformation-data/data_out.csv\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/ammico/notebooks/colors_expression.ipynb b/ammico/notebooks/colors_expression.ipynb deleted file mode 100644 index 0c5f5bbd..00000000 --- a/ammico/notebooks/colors_expression.ipynb +++ /dev/null @@ -1,152 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook shows primary color analysis of color image using K-Means algorithm.\n", - "The output are N primary colors and their corresponding percentage." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.cluster import KMeans\n", - "import matplotlib.pyplot as plt\n", - "import cv2\n", - "import numpy as np\n", - "import requests" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def centroid_histogram(clt):\n", - " # grab the number of different clusters and create a histogram\n", - " # based on the number of pixels assigned to each cluster\n", - " numLabels = np.arange(0, len(np.unique(clt.labels_)) + 1)\n", - " (hist, _) = np.histogram(clt.labels_, bins=numLabels)\n", - "\n", - " # normalize the histogram, such that it sums to one\n", - " hist = hist.astype(\"float\")\n", - " hist /= hist.sum()\n", - "\n", - " # return the histogram\n", - " return hist\n", - "\n", - "\n", - "def plot_colors(hist, centroids):\n", - " # initialize the bar chart representing the relative frequency\n", - " # of each of the colors\n", - " bar = np.zeros((50, 300, 3), dtype=\"uint8\")\n", - " startX = 0\n", - " # loop over the percentage of each cluster and the color of\n", - " # each cluster\n", - " for percent, color in zip(hist, centroids):\n", - " # plot the relative percentage of each cluster\n", - " endX = startX + (percent * 300)\n", - " cv2.rectangle(\n", - " bar, (int(startX), 0), (int(endX), 50), color.astype(\"uint8\").tolist(), -1\n", - " )\n", - " startX = endX\n", - "\n", - " # return the bar chart\n", - " return bar" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# load the image and convert it from BGR to RGB so that\n", - "# we can dispaly it with matplotlib\n", - "# image_path = './data/blue.jpg'\n", - "# image = cv2.imread(image_path)\n", - "\n", - "file = requests.get(\n", - " \"https://heibox.uni-heidelberg.de/thumbnail/537e6da0a8b44069bc96/1024/images/100361_asm.png\"\n", - ")\n", - "image = cv2.imdecode(np.fromstring(file.content, np.uint8), 1)\n", - "\n", - "# BGR-->RGB cv to matplotlib show\n", - "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n", - "\n", - "# show our image\n", - "plt.figure()\n", - "plt.axis(\"off\")\n", - "plt.imshow(image)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# reshape the image to be a list of pixels\n", - "image = image.reshape((image.shape[0] * image.shape[1], 3))\n", - "\n", - "# cluster the pixel intensities\n", - "clt = KMeans(n_clusters=8)\n", - "clt.fit(image)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# build a histogram of clusters and then create a figure\n", - "# representing the number of pixels labeled to each color\n", - "hist = centroid_histogram(clt)\n", - "bar = plot_colors(hist, clt.cluster_centers_)\n", - "\n", - "# show our color bart\n", - "plt.figure()\n", - "plt.axis(\"off\")\n", - "plt.imshow(bar)\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for percent, color in zip(hist, clt.cluster_centers_):\n", - " print(\"color:\", color, \" percentage:\", percent)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/ammico/test/test_colors.py b/ammico/test/test_colors.py new file mode 100644 index 00000000..8600423c --- /dev/null +++ b/ammico/test/test_colors.py @@ -0,0 +1,55 @@ +from ammico.colors import ColorDetector +import pytest + + +def test_set_keys(): + colors = { + "red": 0, + "green": 0, + "blue": 0, + "yellow": 0, + "cyan": 0, + "orange": 0, + "purple": 0, + "pink": 0, + "brown": 0, + "grey": 0, + "white": 0, + "black": 0, + } + cd = ColorDetector({}) + + for color_key, value in colors.items(): + assert cd.subdict[color_key] == value + + +def test_rgb2name(get_path): + cd = ColorDetector({}) + + assert cd.rgb2name([0, 0, 0]) == "black" + assert cd.rgb2name([255, 255, 255]) == "white" + assert cd.rgb2name([205, 133, 63]) == "brown" + + assert cd.rgb2name([255, 255, 255], merge_color=False) == "white" + assert cd.rgb2name([0, 0, 0], merge_color=False) == "black" + assert cd.rgb2name([205, 133, 63], merge_color=False) == "peru" + + with pytest.raises(ValueError): + cd.rgb2name([1, 2]) + + with pytest.raises(ValueError): + cd.rgb2name([1, 2, 3, 4]) + + +def test_analyze_images(get_path): + mydict_1 = { + "filename": get_path + "IMG_2809.png", + } + + test1 = ColorDetector(mydict_1, delta_e_method="CIE 2000").analyse_image() + assert test1["red"] == 0.0 + assert round(test1["green"], 2) == 0.62 + + test2 = ColorDetector(mydict_1).analyse_image() + assert test2["red"] == 0.0 + assert test2["green"] == 0.05 diff --git a/ammico/utils.py b/ammico/utils.py index 3df55971..4bfaaa9b 100644 --- a/ammico/utils.py +++ b/ammico/utils.py @@ -1,6 +1,6 @@ import glob import os -from pandas import DataFrame +from pandas import DataFrame, read_csv import pooch @@ -107,3 +107,17 @@ def is_interactive(): import __main__ as main return not hasattr(main, "__file__") + + +def get_color_table(): + df_colors = read_csv( + os.path.join(os.path.dirname(__file__), "data", "Color_tables.csv"), + delimiter=";", + dtype=str, + encoding="UTF-8", + header=[0, 1], + ) + return { + col_key: df_colors[col_key].dropna().to_dict("list") + for col_key in df_colors.columns.levels[0] + } diff --git a/docs/source/ammico.rst b/docs/source/ammico.rst index 17ba466d..7ccf1c5a 100644 --- a/docs/source/ammico.rst +++ b/docs/source/ammico.rst @@ -29,6 +29,14 @@ faces module :members: :undoc-members: :show-inheritance: + +color_analysis module +--------------------- + +.. automodule:: color_analysis + :members: + :undoc-members: + :show-inheritance: objects module -------------- diff --git a/docs/source/index.rst b/docs/source/index.rst index 849ba0ef..4dcfc4f1 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -15,6 +15,7 @@ Welcome to AMMICO's documentation! notebooks/Example text notebooks/Example summary notebooks/Example multimodal + notebooks/Example colors notebooks/Example objects notebooks/Example cropposts modules diff --git a/docs/source/notebooks/Example colors.ipynb b/docs/source/notebooks/Example colors.ipynb new file mode 100644 index 00000000..d7f0bdea --- /dev/null +++ b/docs/source/notebooks/Example colors.ipynb @@ -0,0 +1,195 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Color analysis of pictures\n", + "\n", + "\n", + "\n", + "This notebook shows primary color analysis of color image using K-Means algorithm.\n", + "The output are N primary colors and their corresponding percentage.\n", + "\n", + "The first cell is only run on google colab and installs the [ammico](https://github.com/ssciwr/AMMICO) package.\n", + "\n", + "After that, we can import `ammico` and read in the files given a folder path." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# if running on google colab\n", + "# flake8-noqa-cell\n", + "import os\n", + "\n", + "if \"google.colab\" in str(get_ipython()):\n", + " # update python version\n", + " # install setuptools\n", + " # %pip install setuptools==61 -qqq\n", + " # install ammico\n", + " %pip install git+https://github.com/ssciwr/ammico.git -qqq\n", + " # mount google drive for data and API key\n", + " from google.colab import drive\n", + "\n", + " drive.mount(\"/content/drive\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import ammico\n", + "from ammico import utils as mutils\n", + "from ammico import display as mdisplay\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We select a subset of image files to try the color analysis on, see the `limit` keyword. The `find_files` function finds image files within a given directory:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Here you need to provide the path to your google drive folder\n", + "# or local folder containing the images\n", + "images = mutils.find_files(\n", + " path=\"/content/drive/MyDrive/misinformation-data/\",\n", + " limit=10,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need to initialize the main dictionary that contains all information for the images and is updated through each subsequent analysis:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mydict = mutils.initialize_dict(images)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To check the analysis, you can inspect the analyzed elements here. Loading the results takes a moment, so please be patient. If you are sure of what you are doing, you can skip this and directly export a csv file in the step below.\n", + "Here, we display the color detection results provided by `colorgram` and `colour` libraries. Click on the tabs to see the results in the right sidebar. You may need to increment the `port` number if you are already running several notebook instances on the same server." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "analysis_explorer = mdisplay.AnalysisExplorer(mydict, identify=\"colors\")\n", + "analysis_explorer.run_server(port = 8057)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instead of inspecting each of the images, you can also directly carry out the analysis and export the result into a csv. This may take a while depending on how many images you have loaded." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for key in mydict.keys():\n", + " mydict[key] = ammico.colors.ColorDetector(mydict[key]).analyse_image()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These steps are required to convert the dictionary of dictionarys into a dictionary with lists, that can be converted into a pandas dataframe and exported to a csv file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "outdict = mutils.append_data_to_dict(mydict)\n", + "df = mutils.dump_df(outdict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check the dataframe:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.head(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Write the csv file - here you should provide a file path and file name for the csv file to be written." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.to_csv(\"/content/drive/MyDrive/misinformation-data/data_out.csv\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/pyproject.toml b/pyproject.toml index c23456cc..89fbed97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,14 +49,29 @@ dependencies = [ "tensorflow", "torch", "transformers", + "google-cloud-vision", + "setuptools", + "opencv-contrib-python", + "dash", + "jupyter_dash", + "dash_renderjson", + "colorgram.py", + "webcolors", + "colour-science", ] [project.scripts] ammico_prefetch_models = "ammico.utils:ammico_prefetch_models" +[project.urls] +homepage = "https://github.com/ssciwr/AMMICO" # FIXME not shown by pip +documentation = "https://ssciwr.github.io/AMMICO/build/html/index.html" + [tool.setuptools] packages = ["ammico"] [tool.setuptools.package-data] # Include any png files found in the "data" subdirectory of "ammico" -"ammico.data" = ["*.png"] \ No newline at end of file +"ammico.data" = ["*.png"] +mypkg = [ "*.csv"] + From d642c8eb7c042b4a872ccfd5bb2acb66cbd91742 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Fri, 23 Jun 2023 13:07:12 +0200 Subject: [PATCH 08/29] fixed code smells --- ammico/summary.py | 2 +- ammico/testing_all.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ammico/summary.py b/ammico/summary.py index e0117ad0..31cd61a7 100644 --- a/ammico/summary.py +++ b/ammico/summary.py @@ -43,7 +43,7 @@ def __init__( self.summary_model_type = summary_model_type self.analysis_type = analysis_type if list_of_questions is None: - list_of_questions = [ + self.list_of_questions = [ "Are there people in the image?", "What is this picture about?", ] diff --git a/ammico/testing_all.py b/ammico/testing_all.py index 57ae6583..9908520d 100755 --- a/ammico/testing_all.py +++ b/ammico/testing_all.py @@ -26,7 +26,3 @@ outdict = ammico.append_data_to_dict(mydict) df = ammico.dump_df(outdict) df.to_csv("data_out4.csv") -# ammico.TextDetector -# ammico.EmotionDetector -# ammico.ObjectDetector -# ammico.SummaryDetector From e4aa158b4bfa895c9c22a332abeaa22119e61b03 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Fri, 23 Jun 2023 14:41:36 +0200 Subject: [PATCH 09/29] adding dropout menu for summary --- ammico/display.py | 75 +++++++++++++++++++++++++++++++++++++++++++ ammico/summary.py | 16 ++++----- ammico/testing_all.py | 13 +++++--- 3 files changed, 90 insertions(+), 14 deletions(-) diff --git a/ammico/display.py b/ammico/display.py index 9ad7bf44..ca38dc8b 100644 --- a/ammico/display.py +++ b/ammico/display.py @@ -24,6 +24,8 @@ "CAM16-UCS", "DIN99", ] +SUMMARY_ANALYSIS_TYPE = ["summary_and_questions", "summary", "questions"] +SUMMARY_MODEL = ["base", "large"] class AnalysisExplorer: @@ -111,6 +113,9 @@ def __init__(self, mydict: dict) -> None: State("setting_Emotion_emotion_threshold", "value"), State("setting_Emotion_race_threshold", "value"), State("setting_Color_delta_e_method", "value"), + State("setting_Summary_analysis_type", "value"), + State("setting_Summary_model", "value"), + State("setting_Summary_list_of_questions", "value"), prevent_initial_call=True, )(self._right_output_analysis) @@ -118,6 +123,7 @@ def __init__(self, mydict: dict) -> None: Output("settings_TextDetector", "style"), Output("settings_EmotionDetector", "style"), Output("settings_ColorDetector", "style"), + Output("settings_Summary_Detector", "style"), Input("Dropdown_select_Detector", "value"), )(self._update_detector_setting) @@ -240,6 +246,62 @@ def _create_setting_layout(self): ) ], ), + html.Div( + id="settings_Summary_Detector", + style={"display": "none"}, + children=[ + html.Div( + [ + dcc.Dropdown( + options=SUMMARY_ANALYSIS_TYPE, + value="summary_and_questions", + id="setting_Summary_analysis_type", + ) + ], + style={ + "width": "49%", + "display": "inline-block", + "margin-top": "10px", + }, + ), + html.Div( + [ + dcc.Dropdown( + options=SUMMARY_MODEL, + value="base", + id="setting_Summary_model", + ) + ], + style={ + "width": "49%", + "display": "inline-block", + "margin-top": "10px", + }, + ), + html.Div( + [ + html.Div( + "Please enter a question", + style={ + "height": "30px", + "margin-top": "5px", + }, + ), + dcc.Input( + type="text", + placeholder="", + id="setting_Summary_list_of_questions", + style={"height": "auto", "margin-bottom": "auto"}, + ), + ], + style={ + "width": "49%", + "display": "inline-block", + "margin-top": "10px", + }, + ), + ], + ), ], ) return settings_layout @@ -342,6 +404,9 @@ def _update_detector_setting(self, setting_input): if setting_input == "ColorDetector": return display_none, display_none, display_flex + if setting_input == "SummaryDetector": + return display_none, display_none, display_flex + else: return display_none, display_none, display_none @@ -355,6 +420,9 @@ def _right_output_analysis( setting_emotion_emotion_threshold: int, setting_emotion_race_threshold: int, setting_color_delta_e_method: str, + setting_Summary_analysis_type: str, + setting_Summary_model: str, + setting_Summary_list_of_questions: str, ) -> dict: """Callback function to perform analysis on the selected image and return the output. @@ -396,6 +464,13 @@ def _right_output_analysis( image_copy, delta_e_method=setting_color_delta_e_method, ) + elif detector_value == "SummaryDetector": + detector_class = identify_function( + image_copy, + analysis_type=setting_Summary_analysis_type, + summary_model_type=setting_Summary_model, + list_of_questions=list[setting_Summary_list_of_questions], + ) else: detector_class = identify_function(image_copy) return detector_class.analyse_image() diff --git a/ammico/summary.py b/ammico/summary.py index 31cd61a7..9df3a762 100644 --- a/ammico/summary.py +++ b/ammico/summary.py @@ -219,35 +219,31 @@ def analyse_questions(self, list_of_questions: list[str]) -> dict: and (self.summary_vqa_txt_processors is None) ): ( - summary_vqa_model, - summary_vqa_vis_processors, - summary_vqa_txt_processors, + self.summary_vqa_model, + self.summary_vqa_vis_processors, + self.summary_vqa_txt_processors, ) = load_model_and_preprocess( name="blip_vqa", model_type="vqav2", is_eval=True, device=self.summary_device, ) - else: - summary_vqa_model = self.summary_vqa_model - summary_vqa_vis_processors = self.summary_vqa_vis_processors - summary_vqa_txt_processors = self.summary_vqa_txt_processors if len(list_of_questions) > 0: path = self.subdict["filename"] raw_image = Image.open(path).convert("RGB") image = ( - summary_vqa_vis_processors["eval"](raw_image) + self.summary_vqa_vis_processors["eval"](raw_image) .unsqueeze(0) .to(self.summary_device) ) question_batch = [] for quest in list_of_questions: - question_batch.append(summary_vqa_txt_processors["eval"](quest)) + question_batch.append(self.summary_vqa_txt_processors["eval"](quest)) batch_size = len(list_of_questions) image_batch = image.repeat(batch_size, 1, 1, 1) with no_grad(): - answers_batch = summary_vqa_model.predict_answers( + answers_batch = self.summary_vqa_model.predict_answers( samples={"image": image_batch, "text_input": question_batch}, inference_method="generate", ) diff --git a/ammico/testing_all.py b/ammico/testing_all.py index 9908520d..bc2fbd95 100755 --- a/ammico/testing_all.py +++ b/ammico/testing_all.py @@ -6,7 +6,12 @@ ) mydict = ammico.initialize_dict(images) obj = ammico.SummaryDetector() - summary_m, summary_v = obj.load_model("base") + # summary_m, summary_v = obj.load_model("base") + ( + summary_vqa_model, + summary_vqa_vis_processors, + summary_vqa_txt_processors, + ) = obj.load_vqa_model() ( summary_vqa_model, summary_vqa_vis_processors, @@ -15,9 +20,9 @@ for key in mydict: mydict[key] = ammico.SummaryDetector( mydict[key], - analysis_type="summary_and_questions", - summary_model=summary_m, - summary_vis_processors=summary_v, + analysis_type="questions", + # summary_model=summary_m, + # summary_vis_processors=summary_v, summary_vqa_model=summary_vqa_model, summary_vqa_vis_processors=summary_vqa_vis_processors, summary_vqa_txt_processors=summary_vqa_txt_processors, From 14e8147a1f7df563724da2bdbd00cf4517f4543f Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Fri, 23 Jun 2023 16:05:17 +0200 Subject: [PATCH 10/29] added new SummaryDetector to AnalysisExplorer --- ammico/display.py | 31 +++++++++++++++++++------------ ammico/summary.py | 10 ++++++---- ammico/testing_all.py | 23 +++++++++-------------- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/ammico/display.py b/ammico/display.py index ca38dc8b..d0b69c6c 100644 --- a/ammico/display.py +++ b/ammico/display.py @@ -259,9 +259,8 @@ def _create_setting_layout(self): ) ], style={ - "width": "49%", + "width": "33%", "display": "inline-block", - "margin-top": "10px", }, ), html.Div( @@ -273,7 +272,7 @@ def _create_setting_layout(self): ) ], style={ - "width": "49%", + "width": "33%", "display": "inline-block", "margin-top": "10px", }, @@ -283,19 +282,18 @@ def _create_setting_layout(self): html.Div( "Please enter a question", style={ - "height": "30px", + "height": "50px", "margin-top": "5px", }, ), dcc.Input( type="text", - placeholder="", id="setting_Summary_list_of_questions", style={"height": "auto", "margin-bottom": "auto"}, ), ], style={ - "width": "49%", + "width": "33%", "display": "inline-block", "margin-top": "10px", }, @@ -396,19 +394,19 @@ def _update_detector_setting(self, setting_input): } if setting_input == "TextDetector": - return display_flex, display_none, display_none + return display_flex, display_none, display_none, display_none if setting_input == "EmotionDetector": - return display_none, display_flex, display_none + return display_none, display_flex, display_none, display_none if setting_input == "ColorDetector": - return display_none, display_none, display_flex + return display_none, display_none, display_flex, display_none if setting_input == "SummaryDetector": - return display_none, display_none, display_flex + return display_none, display_none, display_none, display_flex else: - return display_none, display_none, display_none + return display_none, display_none, display_none, display_none def _right_output_analysis( self, @@ -465,11 +463,20 @@ def _right_output_analysis( delta_e_method=setting_color_delta_e_method, ) elif detector_value == "SummaryDetector": + if setting_Summary_list_of_questions is None: + current_list_of_questions = [ + "What is the main idea?", + "What is the author's purpose?", + ] + else: + current_list_of_questions = [ + setting_Summary_list_of_questions, + ] detector_class = identify_function( image_copy, analysis_type=setting_Summary_analysis_type, summary_model_type=setting_Summary_model, - list_of_questions=list[setting_Summary_list_of_questions], + list_of_questions=current_list_of_questions, ) else: detector_class = identify_function(image_copy) diff --git a/ammico/summary.py b/ammico/summary.py index 9df3a762..3b98c63d 100644 --- a/ammico/summary.py +++ b/ammico/summary.py @@ -39,9 +39,15 @@ def __init__( """ super().__init__(subdict) + if analysis_type not in ["summary", "questions", "summary_and_questions"]: + raise ValueError( + "analysis_type must be one of 'summary', 'questions' or 'summary_and_questions'" + ) self.summary_device = "cuda" if cuda.is_available() else "cpu" self.summary_model_type = summary_model_type self.analysis_type = analysis_type + if (not isinstance(list_of_questions, list)) or (None in list_of_questions): + raise ValueError("list_of_questions must be a list of string (questions)") if list_of_questions is None: self.list_of_questions = [ "Are there people in the image?", @@ -49,10 +55,6 @@ def __init__( ] else: self.list_of_questions = list_of_questions - if analysis_type not in ["summary", "questions", "summary_and_questions"]: - raise ValueError( - "analysis_type must be one of 'summary', 'questions' or 'summary_and_questions'" - ) if ( (summary_model is None) and (summary_vis_processors is None) diff --git a/ammico/testing_all.py b/ammico/testing_all.py index bc2fbd95..9f032549 100755 --- a/ammico/testing_all.py +++ b/ammico/testing_all.py @@ -7,25 +7,20 @@ mydict = ammico.initialize_dict(images) obj = ammico.SummaryDetector() # summary_m, summary_v = obj.load_model("base") - ( - summary_vqa_model, - summary_vqa_vis_processors, - summary_vqa_txt_processors, - ) = obj.load_vqa_model() - ( - summary_vqa_model, - summary_vqa_vis_processors, - summary_vqa_txt_processors, - ) = obj.load_vqa_model() + # ( + # summary_vqa_model, + # summary_vqa_vis_processors, + # summary_vqa_txt_processors, + # ) = obj.load_vqa_model() for key in mydict: mydict[key] = ammico.SummaryDetector( mydict[key], - analysis_type="questions", + analysis_type="summary_and_questions", # summary_model=summary_m, # summary_vis_processors=summary_v, - summary_vqa_model=summary_vqa_model, - summary_vqa_vis_processors=summary_vqa_vis_processors, - summary_vqa_txt_processors=summary_vqa_txt_processors, + # summary_vqa_model=summary_vqa_model, + # summary_vqa_vis_processors=summary_vqa_vis_processors, + # summary_vqa_txt_processors=summary_vqa_txt_processors, ).analyse_image() print(mydict) outdict = ammico.append_data_to_dict(mydict) From 0100b67ab38b2263b88515108959fd5544a9de97 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Fri, 23 Jun 2023 16:31:45 +0200 Subject: [PATCH 11/29] bug fixing --- ammico/summary.py | 4 ++-- ammico/testing_all.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ammico/summary.py b/ammico/summary.py index 3b98c63d..abaa9c1d 100644 --- a/ammico/summary.py +++ b/ammico/summary.py @@ -46,13 +46,13 @@ def __init__( self.summary_device = "cuda" if cuda.is_available() else "cpu" self.summary_model_type = summary_model_type self.analysis_type = analysis_type - if (not isinstance(list_of_questions, list)) or (None in list_of_questions): - raise ValueError("list_of_questions must be a list of string (questions)") if list_of_questions is None: self.list_of_questions = [ "Are there people in the image?", "What is this picture about?", ] + elif (not isinstance(list_of_questions, list)) or (None in list_of_questions): + raise ValueError("list_of_questions must be a list of string (questions)") else: self.list_of_questions = list_of_questions if ( diff --git a/ammico/testing_all.py b/ammico/testing_all.py index 9f032549..efc272a3 100755 --- a/ammico/testing_all.py +++ b/ammico/testing_all.py @@ -15,7 +15,7 @@ for key in mydict: mydict[key] = ammico.SummaryDetector( mydict[key], - analysis_type="summary_and_questions", + analysis_type="questions", # summary_model=summary_m, # summary_vis_processors=summary_v, # summary_vqa_model=summary_vqa_model, From 978c8369ae23e303af257ba98916fb78766fc7d2 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Fri, 23 Jun 2023 16:40:03 +0200 Subject: [PATCH 12/29] code improving --- ammico/display.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ammico/display.py b/ammico/display.py index d0b69c6c..2cf861ef 100644 --- a/ammico/display.py +++ b/ammico/display.py @@ -463,20 +463,13 @@ def _right_output_analysis( delta_e_method=setting_color_delta_e_method, ) elif detector_value == "SummaryDetector": - if setting_Summary_list_of_questions is None: - current_list_of_questions = [ - "What is the main idea?", - "What is the author's purpose?", - ] - else: - current_list_of_questions = [ - setting_Summary_list_of_questions, - ] detector_class = identify_function( image_copy, analysis_type=setting_Summary_analysis_type, summary_model_type=setting_Summary_model, - list_of_questions=current_list_of_questions, + list_of_questions=[setting_Summary_list_of_questions] + if (setting_Summary_list_of_questions is not None) + else None, ) else: detector_class = identify_function(image_copy) From 05725d9634e07b66dc4ef939fbe3d5f558e0cf96 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Fri, 23 Jun 2023 16:56:00 +0200 Subject: [PATCH 13/29] fixed test_display --- ammico/test/test_display.py | 49 ++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/ammico/test/test_display.py b/ammico/test/test_display.py index 4f51b901..f97f46a4 100644 --- a/ammico/test/test_display.py +++ b/ammico/test/test_display.py @@ -46,18 +46,59 @@ def test_AnalysisExplorer(get_path): assert analysis_explorer.update_picture(None) is None analysis_explorer._right_output_analysis( - 2, all_options_dict, path_img_1, "ObjectDetector", True, 50, 50, "CIE 1976" + 2, + all_options_dict, + path_img_1, + "ObjectDetector", + True, + 50, + 50, + "CIE 1976", + "summary_and_questions", + "base", + None, ) analysis_explorer._right_output_analysis( - 2, all_options_dict, path_img_1, "EmotionDetector", True, 50, 50, "CIE 1976" + 2, + all_options_dict, + path_img_1, + "EmotionDetector", + True, + 50, + 50, + "CIE 1976", + "summary_and_questions", + "base", + None, ) + analysis_explorer._right_output_analysis( - 2, all_options_dict, path_img_1, "SummaryDetector", True, 50, 50, "CIE 1976" + 2, + all_options_dict, + path_img_1, + "SummaryDetector", + True, + 50, + 50, + "CIE 1976", + "summary_and_questions", + "base", + None, ) analysis_explorer._right_output_analysis( - 2, all_options_dict, path_img_1, "ColorDetector", True, 50, 50, "CIE 1976" + 2, + all_options_dict, + path_img_1, + "ColorDetector", + True, + 50, + 50, + "CIE 1976", + "summary_and_questions", + "base", + None, ) with pytest.raises(EnvironmentError): From 9559a7b218979d07901c675fb6a33038c8e00ae8 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Fri, 23 Jun 2023 16:59:49 +0200 Subject: [PATCH 14/29] fixed code smells --- ammico/display.py | 14 +++++++------- ammico/test/test_display.py | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ammico/display.py b/ammico/display.py index 2cf861ef..387e9269 100644 --- a/ammico/display.py +++ b/ammico/display.py @@ -418,9 +418,9 @@ def _right_output_analysis( setting_emotion_emotion_threshold: int, setting_emotion_race_threshold: int, setting_color_delta_e_method: str, - setting_Summary_analysis_type: str, - setting_Summary_model: str, - setting_Summary_list_of_questions: str, + setting_summary_analysis_type: str, + setting_summary_model: str, + setting_summary_list_of_questions: str, ) -> dict: """Callback function to perform analysis on the selected image and return the output. @@ -465,10 +465,10 @@ def _right_output_analysis( elif detector_value == "SummaryDetector": detector_class = identify_function( image_copy, - analysis_type=setting_Summary_analysis_type, - summary_model_type=setting_Summary_model, - list_of_questions=[setting_Summary_list_of_questions] - if (setting_Summary_list_of_questions is not None) + analysis_type=setting_summary_analysis_type, + summary_model_type=setting_summary_model, + list_of_questions=[setting_summary_list_of_questions] + if (setting_summary_list_of_questions is not None) else None, ) else: diff --git a/ammico/test/test_display.py b/ammico/test/test_display.py index f97f46a4..785bd847 100644 --- a/ammico/test/test_display.py +++ b/ammico/test/test_display.py @@ -56,7 +56,7 @@ def test_AnalysisExplorer(get_path): "CIE 1976", "summary_and_questions", "base", - None, + "How many people are in the picture?", ) analysis_explorer._right_output_analysis( @@ -70,7 +70,7 @@ def test_AnalysisExplorer(get_path): "CIE 1976", "summary_and_questions", "base", - None, + "How many people are in the picture?", ) analysis_explorer._right_output_analysis( @@ -84,7 +84,7 @@ def test_AnalysisExplorer(get_path): "CIE 1976", "summary_and_questions", "base", - None, + "How many people are in the picture?", ) analysis_explorer._right_output_analysis( @@ -98,7 +98,7 @@ def test_AnalysisExplorer(get_path): "CIE 1976", "summary_and_questions", "base", - None, + "How many people are in the picture?", ) with pytest.raises(EnvironmentError): From c84be2aa6b06d5efd3add70fec49f2d2c647bbb5 Mon Sep 17 00:00:00 2001 From: Inga Ulusoy Date: Mon, 26 Jun 2023 10:20:38 +0200 Subject: [PATCH 15/29] reduce tests for macos --- ammico/test/test_display.py | 118 ++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/ammico/test/test_display.py b/ammico/test/test_display.py index 785bd847..693c1dd5 100644 --- a/ammico/test/test_display.py +++ b/ammico/test/test_display.py @@ -34,10 +34,10 @@ def test_AnalysisExplorer(get_path): "IMG_2746": {"filename": path_img_2}, } - all_options_dict = { - path_img_1: "IMG_2809", - path_img_2: "IMG_2746", - } + # all_options_dict = { + # path_img_1: "IMG_2809", + # path_img_2: "IMG_2746", + # } analysis_explorer = ammico_display.AnalysisExplorer(mydict) @@ -45,61 +45,61 @@ def test_AnalysisExplorer(get_path): assert analysis_explorer.update_picture(None) is None - analysis_explorer._right_output_analysis( - 2, - all_options_dict, - path_img_1, - "ObjectDetector", - True, - 50, - 50, - "CIE 1976", - "summary_and_questions", - "base", - "How many people are in the picture?", - ) - - analysis_explorer._right_output_analysis( - 2, - all_options_dict, - path_img_1, - "EmotionDetector", - True, - 50, - 50, - "CIE 1976", - "summary_and_questions", - "base", - "How many people are in the picture?", - ) - - analysis_explorer._right_output_analysis( - 2, - all_options_dict, - path_img_1, - "SummaryDetector", - True, - 50, - 50, - "CIE 1976", - "summary_and_questions", - "base", - "How many people are in the picture?", - ) - - analysis_explorer._right_output_analysis( - 2, - all_options_dict, - path_img_1, - "ColorDetector", - True, - 50, - 50, - "CIE 1976", - "summary_and_questions", - "base", - "How many people are in the picture?", - ) + # analysis_explorer._right_output_analysis( + # 2, + # all_options_dict, + # path_img_1, + # "ObjectDetector", + # True, + # 50, + # 50, + # "CIE 1976", + # "summary_and_questions", + # "base", + # "How many people are in the picture?", + # ) + + # analysis_explorer._right_output_analysis( + # 2, + # all_options_dict, + # path_img_1, + # "EmotionDetector", + # True, + # 50, + # 50, + # "CIE 1976", + # "summary_and_questions", + # "base", + # "How many people are in the picture?", + # ) + + # analysis_explorer._right_output_analysis( + # 2, + # all_options_dict, + # path_img_1, + # "SummaryDetector", + # True, + # 50, + # 50, + # "CIE 1976", + # "summary_and_questions", + # "base", + # "How many people are in the picture?", + # ) + + # analysis_explorer._right_output_analysis( + # 2, + # all_options_dict, + # path_img_1, + # "ColorDetector", + # True, + # 50, + # 50, + # "CIE 1976", + # "summary_and_questions", + # "base", + # "How many people are in the picture?", + # ) with pytest.raises(EnvironmentError): analysis_explorer.run_server(port=8050) From 59fb515584b2bb314c6b47dba76c69a5427a8095 Mon Sep 17 00:00:00 2001 From: Inga Ulusoy Date: Mon, 26 Jun 2023 10:51:56 +0200 Subject: [PATCH 16/29] try different tqdm version --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 89fbed97..ea81a62a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ dependencies = [ "tensorflow", "torch", "transformers", + "tqdm==4.41.1", "google-cloud-vision", "setuptools", "opencv-contrib-python", From fd985a697487ca42d2e9ddd9850f5bbbae4ee602 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 11:26:33 +0200 Subject: [PATCH 17/29] disabled MacOS CI testing --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a84e6540..78aa0ab0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: python -m pip install --upgrade pip python -m pip install -e . - name: Run pytest linux (linux-only) - if: matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-latest' + if: matrix.os == 'ubuntu-22.04' run: | cd ammico python -m pytest -m "not gcv and not long" -svv --cov=. --cov-report=xml From 884d2dbfaae96287d7d680d4d69ea4b2aa26e07b Mon Sep 17 00:00:00 2001 From: Inga Ulusoy Date: Mon, 26 Jun 2023 11:45:44 +0200 Subject: [PATCH 18/29] enable tests again; don't run on macos --- .github/workflows/ci.yml | 2 +- ammico/test/test_display.py | 118 ++++++++++++++++++------------------ pyproject.toml | 1 - 3 files changed, 60 insertions(+), 61 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78aa0ab0..5804caaa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04,windows-latest,macos-latest] + os: [ubuntu-22.04,windows-latest] python-version: [3.9] steps: - name: Checkout repository diff --git a/ammico/test/test_display.py b/ammico/test/test_display.py index 693c1dd5..785bd847 100644 --- a/ammico/test/test_display.py +++ b/ammico/test/test_display.py @@ -34,10 +34,10 @@ def test_AnalysisExplorer(get_path): "IMG_2746": {"filename": path_img_2}, } - # all_options_dict = { - # path_img_1: "IMG_2809", - # path_img_2: "IMG_2746", - # } + all_options_dict = { + path_img_1: "IMG_2809", + path_img_2: "IMG_2746", + } analysis_explorer = ammico_display.AnalysisExplorer(mydict) @@ -45,61 +45,61 @@ def test_AnalysisExplorer(get_path): assert analysis_explorer.update_picture(None) is None - # analysis_explorer._right_output_analysis( - # 2, - # all_options_dict, - # path_img_1, - # "ObjectDetector", - # True, - # 50, - # 50, - # "CIE 1976", - # "summary_and_questions", - # "base", - # "How many people are in the picture?", - # ) - - # analysis_explorer._right_output_analysis( - # 2, - # all_options_dict, - # path_img_1, - # "EmotionDetector", - # True, - # 50, - # 50, - # "CIE 1976", - # "summary_and_questions", - # "base", - # "How many people are in the picture?", - # ) - - # analysis_explorer._right_output_analysis( - # 2, - # all_options_dict, - # path_img_1, - # "SummaryDetector", - # True, - # 50, - # 50, - # "CIE 1976", - # "summary_and_questions", - # "base", - # "How many people are in the picture?", - # ) - - # analysis_explorer._right_output_analysis( - # 2, - # all_options_dict, - # path_img_1, - # "ColorDetector", - # True, - # 50, - # 50, - # "CIE 1976", - # "summary_and_questions", - # "base", - # "How many people are in the picture?", - # ) + analysis_explorer._right_output_analysis( + 2, + all_options_dict, + path_img_1, + "ObjectDetector", + True, + 50, + 50, + "CIE 1976", + "summary_and_questions", + "base", + "How many people are in the picture?", + ) + + analysis_explorer._right_output_analysis( + 2, + all_options_dict, + path_img_1, + "EmotionDetector", + True, + 50, + 50, + "CIE 1976", + "summary_and_questions", + "base", + "How many people are in the picture?", + ) + + analysis_explorer._right_output_analysis( + 2, + all_options_dict, + path_img_1, + "SummaryDetector", + True, + 50, + 50, + "CIE 1976", + "summary_and_questions", + "base", + "How many people are in the picture?", + ) + + analysis_explorer._right_output_analysis( + 2, + all_options_dict, + path_img_1, + "ColorDetector", + True, + 50, + 50, + "CIE 1976", + "summary_and_questions", + "base", + "How many people are in the picture?", + ) with pytest.raises(EnvironmentError): analysis_explorer.run_server(port=8050) diff --git a/pyproject.toml b/pyproject.toml index ea81a62a..89fbed97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,6 @@ dependencies = [ "tensorflow", "torch", "transformers", - "tqdm==4.41.1", "google-cloud-vision", "setuptools", "opencv-contrib-python", From 0dcc0a6f2872f48fdb42cdf3ad15cd55a95859d3 Mon Sep 17 00:00:00 2001 From: Inga Ulusoy Date: Mon, 26 Jun 2023 12:21:32 +0200 Subject: [PATCH 19/29] more tests and exceptions for init --- ammico/summary.py | 11 +++++++++- ammico/test/test_summary.py | 43 +++++++++++++++++++++++++++++++++++++ ammico/testing_all.py | 28 ------------------------ 3 files changed, 53 insertions(+), 29 deletions(-) delete mode 100755 ammico/testing_all.py diff --git a/ammico/summary.py b/ammico/summary.py index abaa9c1d..21e5fe91 100644 --- a/ammico/summary.py +++ b/ammico/summary.py @@ -44,6 +44,13 @@ def __init__( "analysis_type must be one of 'summary', 'questions' or 'summary_and_questions'" ) self.summary_device = "cuda" if cuda.is_available() else "cpu" + allowed_model_types = ["base", "large"] + if summary_model_type not in allowed_model_types: + raise ValueError( + "Model type is not allowed - please select one of {}".format( + allowed_model_types + ) + ) self.summary_model_type = summary_model_type self.analysis_type = analysis_type if list_of_questions is None: @@ -51,7 +58,9 @@ def __init__( "Are there people in the image?", "What is this picture about?", ] - elif (not isinstance(list_of_questions, list)) or (None in list_of_questions): + elif (not isinstance(list_of_questions, list)) or ( + not all(isinstance(i, str) for i in list_of_questions) + ): raise ValueError("list_of_questions must be a list of string (questions)") else: self.list_of_questions = list_of_questions diff --git a/ammico/test/test_summary.py b/ammico/test/test_summary.py index f63f7773..8da5c0a6 100644 --- a/ammico/test/test_summary.py +++ b/ammico/test/test_summary.py @@ -102,3 +102,46 @@ def test_analyse_questions(get_dict): test_answers2.append(get_dict[key][list_of_questions[1]]) assert sorted(test_answers) == sorted(list_of_questions_ans) assert sorted(test_answers2) == sorted(list_of_questions_ans2) + + +def test_init_summary(): + sd = sm.SummaryDetector({}, analysis_type="summary") + assert sd.analysis_type == "summary" + with pytest.raises(ValueError): + sm.SummaryDetector({}, analysis_type="something") + list_of_questions = ["Question 1", "Question 2"] + sd = sm.SummaryDetector({}, list_of_questions=list_of_questions) + assert sd.list_of_questions == list_of_questions + with pytest.raises(ValueError): + sm.SummaryDetector({}, list_of_questions={}) + with pytest.raises(ValueError): + sm.SummaryDetector({}, list_of_questions=[None]) + with pytest.raises(ValueError): + sm.SummaryDetector({}, list_of_questions=[0.1]) + sd = sm.SummaryDetector({}) + assert sd.summary_model + assert sd.summary_vis_processors + sd = sm.SummaryDetector({}, summary_model_type="large") + assert sd.summary_model + assert sd.summary_vis_processors + with pytest.raises(ValueError): + sm.SummaryDetector({}, summary_model_type="bla") + ( + summary_vqa_model, + summary_vqa_vis_processors, + summary_vqa_txt_processors, + ) = load_model_and_preprocess( + name="blip_vqa", + model_type="vqav2", + is_eval=True, + device="cpu", + ) + sd = sm.SummaryDetector( + {}, + summary_vqa_model=summary_vqa_model, + summary_vqa_vis_processors=summary_vqa_vis_processors, + summary_vqa_txt_processors=summary_vqa_txt_processors, + ) + assert sd.summary_vqa_model + assert sd.summary_vqa_vis_processors + assert sd.summary_vqa_txt_processors diff --git a/ammico/testing_all.py b/ammico/testing_all.py deleted file mode 100755 index efc272a3..00000000 --- a/ammico/testing_all.py +++ /dev/null @@ -1,28 +0,0 @@ -import ammico - -if __name__ == "__main__": - images = ammico.find_files( - path="../data/test/facebook_screenshots/", pattern="*.jpg" - ) - mydict = ammico.initialize_dict(images) - obj = ammico.SummaryDetector() - # summary_m, summary_v = obj.load_model("base") - # ( - # summary_vqa_model, - # summary_vqa_vis_processors, - # summary_vqa_txt_processors, - # ) = obj.load_vqa_model() - for key in mydict: - mydict[key] = ammico.SummaryDetector( - mydict[key], - analysis_type="questions", - # summary_model=summary_m, - # summary_vis_processors=summary_v, - # summary_vqa_model=summary_vqa_model, - # summary_vqa_vis_processors=summary_vqa_vis_processors, - # summary_vqa_txt_processors=summary_vqa_txt_processors, - ).analyse_image() - print(mydict) - outdict = ammico.append_data_to_dict(mydict) - df = ammico.dump_df(outdict) - df.to_csv("data_out4.csv") From 9ff20b5c9ca8288c492e08ce34ec9f4fadd6081b Mon Sep 17 00:00:00 2001 From: Inga Ulusoy Date: Mon, 26 Jun 2023 13:49:14 +0200 Subject: [PATCH 20/29] reduce number of tests --- ammico/test/test_summary.py | 72 ++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/ammico/test/test_summary.py b/ammico/test/test_summary.py index 8da5c0a6..ded7cb70 100644 --- a/ammico/test/test_summary.py +++ b/ammico/test/test_summary.py @@ -109,39 +109,39 @@ def test_init_summary(): assert sd.analysis_type == "summary" with pytest.raises(ValueError): sm.SummaryDetector({}, analysis_type="something") - list_of_questions = ["Question 1", "Question 2"] - sd = sm.SummaryDetector({}, list_of_questions=list_of_questions) - assert sd.list_of_questions == list_of_questions - with pytest.raises(ValueError): - sm.SummaryDetector({}, list_of_questions={}) - with pytest.raises(ValueError): - sm.SummaryDetector({}, list_of_questions=[None]) - with pytest.raises(ValueError): - sm.SummaryDetector({}, list_of_questions=[0.1]) - sd = sm.SummaryDetector({}) - assert sd.summary_model - assert sd.summary_vis_processors - sd = sm.SummaryDetector({}, summary_model_type="large") - assert sd.summary_model - assert sd.summary_vis_processors - with pytest.raises(ValueError): - sm.SummaryDetector({}, summary_model_type="bla") - ( - summary_vqa_model, - summary_vqa_vis_processors, - summary_vqa_txt_processors, - ) = load_model_and_preprocess( - name="blip_vqa", - model_type="vqav2", - is_eval=True, - device="cpu", - ) - sd = sm.SummaryDetector( - {}, - summary_vqa_model=summary_vqa_model, - summary_vqa_vis_processors=summary_vqa_vis_processors, - summary_vqa_txt_processors=summary_vqa_txt_processors, - ) - assert sd.summary_vqa_model - assert sd.summary_vqa_vis_processors - assert sd.summary_vqa_txt_processors + # list_of_questions = ["Question 1", "Question 2"] + # sd = sm.SummaryDetector({}, list_of_questions=list_of_questions) + # assert sd.list_of_questions == list_of_questions + # with pytest.raises(ValueError): + # sm.SummaryDetector({}, list_of_questions={}) + # with pytest.raises(ValueError): + # sm.SummaryDetector({}, list_of_questions=[None]) + # with pytest.raises(ValueError): + # sm.SummaryDetector({}, list_of_questions=[0.1]) + # sd = sm.SummaryDetector({}) + # assert sd.summary_model + # assert sd.summary_vis_processors + # sd = sm.SummaryDetector({}, summary_model_type="large") + # assert sd.summary_model + # assert sd.summary_vis_processors + # with pytest.raises(ValueError): + # sm.SummaryDetector({}, summary_model_type="bla") + # ( + # summary_vqa_model, + # summary_vqa_vis_processors, + # summary_vqa_txt_processors, + # ) = load_model_and_preprocess( + # name="blip_vqa", + # model_type="vqav2", + # is_eval=True, + # device="cpu", + # ) + # sd = sm.SummaryDetector( + # {}, + # summary_vqa_model=summary_vqa_model, + # summary_vqa_vis_processors=summary_vqa_vis_processors, + # summary_vqa_txt_processors=summary_vqa_txt_processors, + # ) + # assert sd.summary_vqa_model + # assert sd.summary_vqa_vis_processors + # assert sd.summary_vqa_txt_processors From 07f2a2cc4b88e18f898ebb20a9a1e37cb5b8325f Mon Sep 17 00:00:00 2001 From: Inga Ulusoy Date: Mon, 26 Jun 2023 14:04:10 +0200 Subject: [PATCH 21/29] put some tests in again --- ammico/test/test_summary.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ammico/test/test_summary.py b/ammico/test/test_summary.py index ded7cb70..1ae63a52 100644 --- a/ammico/test/test_summary.py +++ b/ammico/test/test_summary.py @@ -109,18 +109,18 @@ def test_init_summary(): assert sd.analysis_type == "summary" with pytest.raises(ValueError): sm.SummaryDetector({}, analysis_type="something") - # list_of_questions = ["Question 1", "Question 2"] - # sd = sm.SummaryDetector({}, list_of_questions=list_of_questions) - # assert sd.list_of_questions == list_of_questions - # with pytest.raises(ValueError): - # sm.SummaryDetector({}, list_of_questions={}) - # with pytest.raises(ValueError): - # sm.SummaryDetector({}, list_of_questions=[None]) - # with pytest.raises(ValueError): - # sm.SummaryDetector({}, list_of_questions=[0.1]) - # sd = sm.SummaryDetector({}) - # assert sd.summary_model - # assert sd.summary_vis_processors + list_of_questions = ["Question 1", "Question 2"] + sd = sm.SummaryDetector({}, list_of_questions=list_of_questions) + assert sd.list_of_questions == list_of_questions + with pytest.raises(ValueError): + sm.SummaryDetector({}, list_of_questions={}) + with pytest.raises(ValueError): + sm.SummaryDetector({}, list_of_questions=[None]) + with pytest.raises(ValueError): + sm.SummaryDetector({}, list_of_questions=[0.1]) + sd = sm.SummaryDetector({}) + assert sd.summary_model + assert sd.summary_vis_processors # sd = sm.SummaryDetector({}, summary_model_type="large") # assert sd.summary_model # assert sd.summary_vis_processors From 23af4282400dfebeb7134c81f650a56db4309681 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 14:20:23 +0200 Subject: [PATCH 22/29] changed CI, runs pytest independently --- .github/workflows/ci.yml | 38 ++++++++++++++++++++++++----- ammico/test/test_summary.py | 48 ++++++++++++++++++------------------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5804caaa..8a000e3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,16 +27,42 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -e . - - name: Run pytest linux (linux-only) - if: matrix.os == 'ubuntu-22.04' + - name: Run pytest test_colors run: | cd ammico - python -m pytest -m "not gcv and not long" -svv --cov=. --cov-report=xml - - name: Run pytest windows(windows-only) - if: matrix.os == 'windows-latest' + python -m pytest test/test_colors.py -svv --cov=. --cov-report=xml + - name: Run pytest test_cropposts run: | cd ammico - python -m pytest -m "not gcv and not long and not win_skip" -svv --cov=. --cov-report=xml + python -m pytest test/test_cropposts.py -svv --cov=. --cov-report=xml + - name: Run pytest test_display + run: | + cd ammico + python -m pytest test/test_display.py -svv --cov=. --cov-report=xml + - name: Run pytest test_faces + run: | + cd ammico + python -m pytest test/test_faces.py -svv --cov=. --cov-report=xml + - name: Run pytest test_multimodal_search + run: | + cd ammico + python -m pytest test/test_multimodal_search.py -svv --cov=. --cov-report=xml + - name: Run pytest test_objects + run: | + cd ammico + python -m pytest test/test_objects.py -svv --cov=. --cov-report=xml + - name: Run pytest test_summary + run: | + cd ammico + python -m pytest test/test_summary.py -svv --cov=. --cov-report=xml + - name: Run pytest test_text + run: | + cd ammico + python -m pytest test/test_text.py -svv --cov=. --cov-report=xml + - name: Run pytest test_utils + run: | + cd ammico + python -m pytest test/test_utils.py -svv --cov=. --cov-report=xml - name: Upload coverage if: matrix.os == 'ubuntu-22.04' && matrix.python-version == '3.9' uses: codecov/codecov-action@v3 diff --git a/ammico/test/test_summary.py b/ammico/test/test_summary.py index 1ae63a52..8da5c0a6 100644 --- a/ammico/test/test_summary.py +++ b/ammico/test/test_summary.py @@ -121,27 +121,27 @@ def test_init_summary(): sd = sm.SummaryDetector({}) assert sd.summary_model assert sd.summary_vis_processors - # sd = sm.SummaryDetector({}, summary_model_type="large") - # assert sd.summary_model - # assert sd.summary_vis_processors - # with pytest.raises(ValueError): - # sm.SummaryDetector({}, summary_model_type="bla") - # ( - # summary_vqa_model, - # summary_vqa_vis_processors, - # summary_vqa_txt_processors, - # ) = load_model_and_preprocess( - # name="blip_vqa", - # model_type="vqav2", - # is_eval=True, - # device="cpu", - # ) - # sd = sm.SummaryDetector( - # {}, - # summary_vqa_model=summary_vqa_model, - # summary_vqa_vis_processors=summary_vqa_vis_processors, - # summary_vqa_txt_processors=summary_vqa_txt_processors, - # ) - # assert sd.summary_vqa_model - # assert sd.summary_vqa_vis_processors - # assert sd.summary_vqa_txt_processors + sd = sm.SummaryDetector({}, summary_model_type="large") + assert sd.summary_model + assert sd.summary_vis_processors + with pytest.raises(ValueError): + sm.SummaryDetector({}, summary_model_type="bla") + ( + summary_vqa_model, + summary_vqa_vis_processors, + summary_vqa_txt_processors, + ) = load_model_and_preprocess( + name="blip_vqa", + model_type="vqav2", + is_eval=True, + device="cpu", + ) + sd = sm.SummaryDetector( + {}, + summary_vqa_model=summary_vqa_model, + summary_vqa_vis_processors=summary_vqa_vis_processors, + summary_vqa_txt_processors=summary_vqa_txt_processors, + ) + assert sd.summary_vqa_model + assert sd.summary_vqa_vis_processors + assert sd.summary_vqa_txt_processors From d09480934e1c9abe8bc4cce0dbef9d0dddbd8c69 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 14:27:01 +0200 Subject: [PATCH 23/29] added not gcv flag for pytest test/test_text.py command in CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a000e3c..5984a7c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: - name: Run pytest test_text run: | cd ammico - python -m pytest test/test_text.py -svv --cov=. --cov-report=xml + python -m pytest test/test_text.py -m "not gcv" -svv --cov=. --cov-report=xml - name: Run pytest test_utils run: | cd ammico From 0e911e01686e69a2b94e2415efb79189ad1d6a53 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 14:49:22 +0200 Subject: [PATCH 24/29] added not long flag to CI tests --- .github/workflows/ci.yml | 4 ++-- ammico/test/test_multimodal_search.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5984a7c8..47954248 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: - name: Run pytest test_multimodal_search run: | cd ammico - python -m pytest test/test_multimodal_search.py -svv --cov=. --cov-report=xml + python -m pytest test/test_multimodal_search.py -m "not long" -svv --cov=. --cov-report=xml - name: Run pytest test_objects run: | cd ammico @@ -54,7 +54,7 @@ jobs: - name: Run pytest test_summary run: | cd ammico - python -m pytest test/test_summary.py -svv --cov=. --cov-report=xml + python -m pytest test/test_summary.py -m "not long" -svv --cov=. --cov-report=xml - name: Run pytest test_text run: | cd ammico diff --git a/ammico/test/test_multimodal_search.py b/ammico/test/test_multimodal_search.py index e3ae7911..c40264bc 100644 --- a/ammico/test/test_multimodal_search.py +++ b/ammico/test/test_multimodal_search.py @@ -443,7 +443,7 @@ def test_parsing_images( cuda.empty_cache() -@pytest.mark.long +# @pytest.mark.long def test_itm(get_test_my_dict, get_path): search_query3 = [ {"text_input": "A bus"}, From 332b3447ec55719130035782aac586866236a0a1 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 15:15:18 +0200 Subject: [PATCH 25/29] added macos to CI and disable long test in multimodal_search --- .github/workflows/ci.yml | 2 +- ammico/test/test_multimodal_search.py | 2 +- ammico/test/test_summary.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47954248..2419973a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04,windows-latest] + os: [ubuntu-22.04,windows-latest,macos-latest] python-version: [3.9] steps: - name: Checkout repository diff --git a/ammico/test/test_multimodal_search.py b/ammico/test/test_multimodal_search.py index c40264bc..e3ae7911 100644 --- a/ammico/test/test_multimodal_search.py +++ b/ammico/test/test_multimodal_search.py @@ -443,7 +443,7 @@ def test_parsing_images( cuda.empty_cache() -# @pytest.mark.long +@pytest.mark.long def test_itm(get_test_my_dict, get_path): search_query3 = [ {"text_input": "A bus"}, diff --git a/ammico/test/test_summary.py b/ammico/test/test_summary.py index 8da5c0a6..287938e2 100644 --- a/ammico/test/test_summary.py +++ b/ammico/test/test_summary.py @@ -40,7 +40,7 @@ def get_dict(get_path): return mydict -@pytest.mark.long +# @pytest.mark.long def test_analyse_image(get_dict): reference_results = { "run1": { From e91a46247a1328688e671b4e834e1961133b5e4a Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 15:42:26 +0200 Subject: [PATCH 26/29] exclude test_analysisExplorer from macos in CI --- ammico/test/test_display.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ammico/test/test_display.py b/ammico/test/test_display.py index 785bd847..3a2253eb 100644 --- a/ammico/test/test_display.py +++ b/ammico/test/test_display.py @@ -1,6 +1,7 @@ import json import ammico.display as ammico_display import pytest +import sys def test_explore_analysis_faces(get_path): @@ -25,6 +26,7 @@ def test_explore_analysis_objects(get_path): assert sub_dict[key] == outs[key] +@pytest.mark.skipif(sys.platform == "darwin", reason="segmentation fault on mac") def test_AnalysisExplorer(get_path): path_img_1 = get_path + "IMG_2809.png" path_img_2 = get_path + "IMG_2746.png" From 17a18045b22dd08562ac66e9789bc1a22100dc3a Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 16:05:50 +0200 Subject: [PATCH 27/29] Exclude another test from macos --- ammico/test/test_objects.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ammico/test/test_objects.py b/ammico/test/test_objects.py index 36b085ae..6bad030b 100644 --- a/ammico/test/test_objects.py +++ b/ammico/test/test_objects.py @@ -2,6 +2,7 @@ import pytest import ammico.objects as ob import ammico.objects_cvlib as ob_cvlib +import sys OBJECT_1 = "cell phone" OBJECT_2 = "motorcycle" @@ -25,6 +26,7 @@ def test_objects_from_cvlib(default_objects): assert str(objects) == str(out_objects) +@pytest.mark.skipif(sys.platform == "darwin", reason="segmentation fault on mac") def test_analyse_image_cvlib(get_path): mydict = {"filename": get_path + TEST_IMAGE_1} ob_cvlib.ObjectCVLib().analyse_image(mydict) From a4ab433d4923a05f9fbcafc8818fb8b4548cd76d Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 16:30:51 +0200 Subject: [PATCH 28/29] Exclude another 3 tests from macos --- ammico/test/test_objects.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ammico/test/test_objects.py b/ammico/test/test_objects.py index 6bad030b..bcd536f5 100644 --- a/ammico/test/test_objects.py +++ b/ammico/test/test_objects.py @@ -57,6 +57,7 @@ def test_init_default_objects(): assert init_objects[obj] == "no" +@pytest.mark.skipif(sys.platform == "darwin", reason="segmentation fault on mac") def test_analyse_image_from_file_cvlib(get_path): file_path = get_path + TEST_IMAGE_1 objs = ob_cvlib.ObjectCVLib().analyse_image_from_file(file_path) @@ -68,6 +69,7 @@ def test_analyse_image_from_file_cvlib(get_path): assert objs[key] == out_dict[key] +@pytest.mark.skipif(sys.platform == "darwin", reason="segmentation fault on mac") def test_detect_objects_cvlib(get_path): file_path = get_path + TEST_IMAGE_1 objs = ob_cvlib.ObjectCVLib().detect_objects_cvlib(file_path) @@ -84,6 +86,7 @@ def test_set_keys(default_objects, get_path): assert str(default_objects) == str(key_objs) +@pytest.mark.skipif(sys.platform == "darwin", reason="segmentation fault on mac") def test_analyse_image(get_path): mydict = {"filename": get_path + TEST_IMAGE_1} ob.ObjectDetector.set_client_to_cvlib() From f29a01c81323b4a58875b4f268999b0443357e48 Mon Sep 17 00:00:00 2001 From: Petr Andriushchenko Date: Mon, 26 Jun 2023 17:00:13 +0200 Subject: [PATCH 29/29] moved some tests from test_init_summary to test_advanced_init_summary and mark them as long --- ammico/test/test_summary.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ammico/test/test_summary.py b/ammico/test/test_summary.py index 287938e2..b6388413 100644 --- a/ammico/test/test_summary.py +++ b/ammico/test/test_summary.py @@ -118,6 +118,10 @@ def test_init_summary(): sm.SummaryDetector({}, list_of_questions=[None]) with pytest.raises(ValueError): sm.SummaryDetector({}, list_of_questions=[0.1]) + + +@pytest.mark.long +def test_advanced_init_summary(): sd = sm.SummaryDetector({}) assert sd.summary_model assert sd.summary_vis_processors