diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14cb8fdd..f9119718 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,10 +36,10 @@ jobs: run: | cd ammico python -m pytest test/test_cropposts.py -svv --cov=. --cov-report=xml --cov-append - # - name: Run pytest test_display - # run: | - # cd ammico - # python -m pytest test/test_display.py -svv --cov=. --cov-report=xml --cov-append + - name: Run pytest test_display + run: | + cd ammico + python -m pytest test/test_display.py -svv --cov=. --cov-report=xml --cov-append - name: Run pytest test_faces run: | cd ammico @@ -48,11 +48,7 @@ jobs: run: | cd ammico python -m pytest test/test_multimodal_search.py -m "not long" -svv --cov=. --cov-report=xml --cov-append - # - name: Run pytest test_objects - # run: | - # cd ammico - # python -m pytest test/test_objects.py -svv --cov=. --cov-report=xml --cov-append - - name: Clear cache ubuntu + - name: Clear cache ubuntu 1 if: matrix.os == 'ubuntu-22.04' run: | rm -rf ~/.cache/* @@ -60,7 +56,7 @@ jobs: run: | cd ammico python -m pytest test/test_summary.py -m "not long" -svv --cov=. --cov-report=xml --cov-append - - name: Clear cache2 + - name: Clear cache ubuntu 2 if: matrix.os == 'ubuntu-22.04' run: | rm -rf ~/.cache/* diff --git a/ammico/__init__.py b/ammico/__init__.py index 67badfd8..7f1465ff 100644 --- a/ammico/__init__.py +++ b/ammico/__init__.py @@ -7,7 +7,6 @@ from ammico.display import AnalysisExplorer from ammico.faces import EmotionDetector from ammico.multimodal_search import MultimodalSearch -from ammico.objects import ObjectDetector from ammico.summary import SummaryDetector from ammico.text import TextDetector, PostprocessText from ammico.utils import find_files, get_dataframe @@ -22,7 +21,6 @@ "AnalysisExplorer", "EmotionDetector", "MultimodalSearch", - "ObjectDetector", "SummaryDetector", "TextDetector", "PostprocessText", diff --git a/ammico/display.py b/ammico/display.py index a69cdadb..11e70357 100644 --- a/ammico/display.py +++ b/ammico/display.py @@ -1,6 +1,5 @@ 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 @@ -332,7 +331,6 @@ def _right_output_json(self) -> html.Div: dcc.Dropdown( options=[ "TextDetector", - "ObjectDetector", "EmotionDetector", "SummaryDetector", "ColorDetector", @@ -465,7 +463,6 @@ def _right_output_analysis( identify_dict = { "EmotionDetector": faces.EmotionDetector, "TextDetector": text.TextDetector, - "ObjectDetector": objects.ObjectDetector, "SummaryDetector": summary.SummaryDetector, "ColorDetector": colors.ColorDetector, } diff --git a/ammico/notebooks/DemoNotebook_ammico.ipynb b/ammico/notebooks/DemoNotebook_ammico.ipynb index dca069cc..243984a7 100644 --- a/ammico/notebooks/DemoNotebook_ammico.ipynb +++ b/ammico/notebooks/DemoNotebook_ammico.ipynb @@ -226,17 +226,7 @@ "```\n", "image_dict[\"image_id\"] = ammico.EmotionDetector(image_dict[\"image_id\"], emotion_threshold=50, race_threshold=50).analyse_image()\n", "```\n", - "The thresholds can be adapted interactively in the notebook interface and the optimal value can then be used in a subsequent analysis of the whole data set.\n", - "\n", - "## Object detection\n", - "Certain specified objects on the image are detected with the cvlib library and YOLOv4 model. Of the 80 objects from the [yolov library](https://github.com/AlexeyAB/darknet/blob/master/data/coco.names), the detection is restricted to person, bicycle, car, motorcycle, airplane, bus, train, truck, boat, traffic light.\n", - "\n", - "The analysis returns a dictionary with \"yes\" or \"no\" answers for the detected items: `\"person\": \"yes\", \"bicycle\": \"no\", \"car\": \"no\", \"motorcycle\": \"no\", \"airplane\": \"no\", \"bus\": \"no\", \"train\": \"no\", \"truck\": \"no\", \"boat\": \"no\", \"traffic light\": \"no\", \"cell phone\": \"no\"`.\n", - "\n", - "The object detection is very straightforward with no further parameters, and is called using\n", - "```\n", - "image_dict[\"image_id\"] = ammico.ObjectDetector(image_dict[\"image_id\"]).analyse_image()\n", - "```" + "The thresholds can be adapted interactively in the notebook interface and the optimal value can then be used in a subsequent analysis of the whole data set." ] }, { diff --git a/ammico/notebooks/objects_expression.ipynb b/ammico/notebooks/objects_expression.ipynb deleted file mode 100644 index d6b7d47a..00000000 --- a/ammico/notebooks/objects_expression.ipynb +++ /dev/null @@ -1,203 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Objects recognition" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebooks shows how to detect objects quickly 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.\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" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Set an image path as input file path." - ] - }, - { - "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", - "mydict = ammico.find_files(\n", - " path=\"/content/drive/MyDrive/misinformation-data/\",\n", - " limit=10,\n", - ")\n", - "mydict" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Detect objects and directly write to csv\n", - "You can 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:\n", - " mydict[key] = ammico.ObjectDetector(mydict[key]).analyse_image()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Convert the dictionary of dictionarys into a dictionary with lists:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "outdict = ammico.append_data_to_dict(mydict)\n", - "df = ammico.dump_df(outdict)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Check the dataframe:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df.head(10)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Write the csv file:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df.to_csv(\"/content/drive/MyDrive/misinformation-data/data_out.csv\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Manually inspect what was detected\n", - "\n", - "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 directly export a csv file in the step above.\n", - "Here, we display the object detection results provided by the above library. 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 = ammico.AnalysisExplorer(mydict)\n", - "analysis_explorer.run_server(port=8056)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "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.11.3" - }, - "vscode": { - "interpreter": { - "hash": "f1142466f556ab37fe2d38e2897a16796906208adb09fea90ba58bdf8a56f0ba" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/ammico/objects.py b/ammico/objects.py deleted file mode 100644 index 9bbd64de..00000000 --- a/ammico/objects.py +++ /dev/null @@ -1,54 +0,0 @@ -from ammico.utils import AnalysisMethod -from ammico.objects_cvlib import ObjectCVLib -from ammico.objects_cvlib import init_default_objects - - -class ObjectDetectorClient(AnalysisMethod): - def __init__(self): - # The detector is set to CVLib by default - self.detector = ObjectCVLib() - - def set_client_to_cvlib(self): - """Set the object detection client to use CVLib.""" - self.detector = ObjectCVLib() - - def analyse_image(self, subdict=None): - """Localize objects in the given image. - - Args: - subdict (dict): The dictionary for an image expression instance. - - Returns: - dict: The updated dictionary with object detection results. - """ - return self.detector.analyse_image(subdict) - - -class ObjectDetector(AnalysisMethod): - od_client = ObjectDetectorClient() - - def __init__(self, subdict: dict): - super().__init__(subdict) - self.subdict.update(self.set_keys()) - - def set_keys(self): - """Set the default object keys for analysis. - - Returns: - dict: The dictionary with default object keys. - """ - return init_default_objects() - - def analyse_image(self): - """Perform object detection on the image. - - Returns: - dict: The updated dictionary with object detection results. - """ - self.subdict = ObjectDetector.od_client.analyse_image(self.subdict) - return self.subdict - - @staticmethod - def set_client_to_cvlib(): - """Set the object detection client to use CVLib.""" - ObjectDetector.od_client.set_client_to_cvlib() diff --git a/ammico/objects_cvlib.py b/ammico/objects_cvlib.py deleted file mode 100644 index a2a68261..00000000 --- a/ammico/objects_cvlib.py +++ /dev/null @@ -1,77 +0,0 @@ -import cv2 -import cvlib as cv - - -def objects_from_cvlib(objects_list: list) -> dict: - objects = init_default_objects() - for key in objects: - if key in objects_list: - objects[key] = "yes" - return objects - - -def init_default_objects(): - objects = { - "person": "no", - "bicycle": "no", - "car": "no", - "motorcycle": "no", - "airplane": "no", - "bus": "no", - "train": "no", - "truck": "no", - "boat": "no", - "traffic light": "no", - "cell phone": "no", - } - return objects - - -class ObjectsMethod: - """Base class to be inherited by all objects methods.""" - - def __init__(self): - # initialize in child class - pass - - def analyse_image(self, subdict): - raise NotImplementedError() - - -class ObjectCVLib(ObjectsMethod): - def __init__(self, client_type=1): - # as long as imageai is not activated this remains empty - pass - - def detect_objects_cvlib(self, image_path): - """Localize objects in the local image. - - Args: - image_path: The path to the local file. - """ - img = cv2.imread(image_path) - - _, label, _ = cv.detect_common_objects(img) - objects = objects_from_cvlib(label) - return objects - - def analyse_image_from_file(self, image_path): - """Localize objects in the local image. - - Args: - image_path: The path to the local file. - """ - objects = self.detect_objects_cvlib(image_path) - return objects - - def analyse_image(self, subdict): - """Localize objects in the local image. - - Args: - subdict: The dictionary for an image expression instance. - """ - objects = self.analyse_image_from_file(subdict["filename"]) - for key in objects: - subdict[key] = objects[key] - - return subdict diff --git a/ammico/test/data/example_analysis_objects.json b/ammico/test/data/example_analysis_objects.json deleted file mode 100644 index 89e9e6b5..00000000 --- a/ammico/test/data/example_analysis_objects.json +++ /dev/null @@ -1 +0,0 @@ -{"person": "yes", "bicycle": "no", "car": "yes", "motorcycle": "no", "airplane": "no", "bus": "yes", "train": "no", "truck": "no", "boat": "no", "traffic light": "no", "cell phone": "no"} diff --git a/ammico/test/data/example_objects_cvlib.json b/ammico/test/data/example_objects_cvlib.json deleted file mode 100644 index 2b0ee03b..00000000 --- a/ammico/test/data/example_objects_cvlib.json +++ /dev/null @@ -1 +0,0 @@ -{"filename": "IMG_2809.png", "person": "yes", "bicycle": "no", "car": "yes", "motorcycle": "no", "airplane": "no", "bus": "yes", "train": "no", "truck": "no", "boat": "no", "traffic light": "no", "cell phone": "no"} \ No newline at end of file diff --git a/ammico/test/test_display.py b/ammico/test/test_display.py index fcaec508..e00c06ae 100644 --- a/ammico/test/test_display.py +++ b/ammico/test/test_display.py @@ -37,40 +37,11 @@ def test_explore_analysis_faces(get_path): assert sub_dict[key] == outs[key] -def test_explore_analysis_objects(get_path): - mydict = {"IMG_2809": {"filename": get_path + "IMG_2809.png"}} - with open(get_path + "example_analysis_objects.json", "r") as file: - outs = json.load(file) - mydict["IMG_2809"].pop("filename", None) - for im_key in mydict.keys(): - sub_dict = mydict[im_key] - for key in sub_dict.keys(): - assert sub_dict[key] == outs[key] - - def test_AnalysisExplorer(get_AE, get_options): get_AE.update_picture(get_options[0]) assert get_AE.update_picture(None) is None -def test_right_output_analysis_objects(get_AE, get_options): - get_AE._right_output_analysis( - 2, - get_options[3], - get_options[0], - "ObjectDetector", - True, - None, - None, - 50, - 50, - "CIE 1976", - "summary_and_questions", - "base", - "How many people are in the picture?", - ) - - def test_right_output_analysis_emotions(get_AE, get_options): get_AE._right_output_analysis( 2, diff --git a/ammico/test/test_objects.py b/ammico/test/test_objects.py deleted file mode 100644 index 2560bd56..00000000 --- a/ammico/test/test_objects.py +++ /dev/null @@ -1,94 +0,0 @@ -import json -import pytest -import ammico.objects as ob -import ammico.objects_cvlib as ob_cvlib -import sys - -OBJECT_1 = "cell phone" -OBJECT_2 = "motorcycle" -OBJECT_3 = "traffic light" -TEST_IMAGE_1 = "IMG_2809.png" -JSON_1 = "example_objects_cvlib.json" - - -@pytest.fixture() -def default_objects(): - return ob.init_default_objects() - - -def test_objects_from_cvlib(default_objects): - objects_list = [OBJECT_1, OBJECT_2, OBJECT_3] - objects = ob_cvlib.objects_from_cvlib(objects_list) - out_objects = default_objects - for obj in objects_list: - out_objects[obj] = "yes" - - assert str(objects) == str(out_objects) - - -def test_analyse_image_cvlib(get_path): - mydict = {"filename": get_path + TEST_IMAGE_1} - ob_cvlib.ObjectCVLib().analyse_image(mydict) - - with open(get_path + JSON_1, "r") as file: - out_dict = json.load(file) - out_dict["filename"] = get_path + out_dict["filename"] - for key in mydict.keys(): - assert mydict[key] == out_dict[key] - - -def test_init_default_objects(): - default_obj_list = [ - "person", - "bicycle", - "car", - OBJECT_2, - "airplane", - "bus", - "train", - "truck", - "boat", - OBJECT_3, - OBJECT_1, - ] - init_objects = ob_cvlib.init_default_objects() - for obj in default_obj_list: - assert init_objects[obj] == "no" - - -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) - - with open(get_path + JSON_1, "r") as file: - out_dict = json.load(file) - out_dict["filename"] = get_path + out_dict["filename"] - for key in objs.keys(): - assert objs[key] == out_dict[key] - - -def test_detect_objects_cvlib(get_path): - file_path = get_path + TEST_IMAGE_1 - objs = ob_cvlib.ObjectCVLib().detect_objects_cvlib(file_path) - - with open(get_path + JSON_1, "r") as file: - out_dict = json.load(file) - for key in objs.keys(): - assert objs[key] == out_dict[key] - - -def test_set_keys(default_objects, get_path): - mydict = {"filename": get_path + TEST_IMAGE_1} - key_objs = ob.ObjectDetector(mydict).set_keys() - assert str(default_objects) == str(key_objs) - - -def test_analyse_image(get_path): - mydict = {"filename": get_path + TEST_IMAGE_1} - ob.ObjectDetector.set_client_to_cvlib() - ob.ObjectDetector(mydict).analyse_image() - with open(get_path + JSON_1, "r") as file: - out_dict = json.load(file) - out_dict["filename"] = get_path + out_dict["filename"] - - assert str(mydict) == str(out_dict) diff --git a/docs/source/notebooks/Example objects.ipynb b/docs/source/notebooks/Example objects.ipynb deleted file mode 100644 index 3fa9095c..00000000 --- a/docs/source/notebooks/Example objects.ipynb +++ /dev/null @@ -1,214 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Objects recognition" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebooks shows how to detect objects quickly 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.\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", - "import ammico.objects as ob" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Set an image path as input file path." - ] - }, - { - "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=\"data/\",\n", - " limit=10,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mydict = mutils.initialize_dict(images)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Detect objects and directly write to csv\n", - "You can 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:\n", - " mydict[key] = ob.ObjectDetector(mydict[key]).analyse_image()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Convert the dictionary of dictionarys into a dictionary with lists:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "outdict = mutils.append_data_to_dict(mydict)\n", - "df = mutils.dump_df(outdict)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Check the dataframe:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df.head(10)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Write the csv file:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df.to_csv(\"data_out.csv\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Manually inspect what was detected\n", - "\n", - "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 directly export a csv file in the step above.\n", - "Here, we display the object detection results provided by the above library. 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=\"objects\")\n", - "analysis_explorer.run_server(port=8056)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "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" - }, - "vscode": { - "interpreter": { - "hash": "f1142466f556ab37fe2d38e2897a16796906208adb09fea90ba58bdf8a56f0ba" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/pyproject.toml b/pyproject.toml index 8a258119..2b2215cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,6 @@ classifiers = [ dependencies = [ "bertopic<=0.14.1", - "cvlib @ git+https://github.com/iulusoy/cvlib.git@iulusoy-patch-1", "dash>=2.11.0", "deepface<=0.0.75", "googletrans==3.1.0a0",