* increased dash width

* added new color_analysis notebook

* added colorgram.py to dependencies

* added first iteration of new color_check

* added new version of color analysis

* added webcolors to dependencies

* added colormath

* switched from colormath to colour-science

* made delta_e algorithm user accessible

* remove obsolete notebook

* update docstrings and type hints

* add color analysis module to API doc

* renamed color_expressions to color_analysis

* renamed test

* updated color analysis notebook to adhere to the same style as other notebooks

* updated test for new df orientation

* refactored color analysis to comply with ammico workflow

* updated color tests to comply with new class structure

* added explanation to colors_analysis notebook

* added class doc string

* updated analysis explorer test to include empty image keyword as dash observer

* fix typo and names, docstring and import

* update doc and notebook explanation

* add project url for pypi

---------

Co-authored-by: Inga Ulusoy <inga.ulusoy@uni-heidelberg.de>
Этот коммит содержится в:
GwydionJon 2023-06-22 13:58:49 +02:00 коммит произвёл GitHub
родитель aedd166d7e
Коммит 1d9e1338ea
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 649 добавлений и 166 удалений

Просмотреть файл

@ -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.

118
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

24
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;;;;;;;;;;;;
1 Pink Pink purple purple red red orange orange yellow yellow green green cyan cyan blue blue brown brown white white grey grey black black
2 ColorName HEX ColorName HEX ColorName HEX ColorName HEX ColorName HEX ColorName HEX ColorName HEX ColorName HEX ColorName HEX ColorName HEX ColorName HEX ColorName HEX
3 Pink #FFC0CB Lavender #E6E6FA LightSalmon #FFA07A Orange #FFA500 Gold #FFD700 GreenYellow #ADFF2F Aqua #00FFFF CadetBlue #5F9EA0 Cornsilk #FFF8DC White #FFFFFF Gainsboro #DCDCDC Black #000000
4 LightPink #FFB6C1 Thistle #D8BFD8 Salmon #FA8072 DarkOrange #FF8C00 Yellow #FFFF00 Chartreuse #7FFF00 Cyan #00FFFF SteelBlue #4682B4 BlanchedAlmond #FFEBCD Snow #FFFAFA LightGray #D3D3D3
5 HotPink #FF69B4 Plum #DDA0DD DarkSalmon #E9967A Coral #FF7F50 LightYellow #FFFFE0 LawnGreen #7CFC00 LightCyan #E0FFFF LightSteelBlue #B0C4DE Bisque #FFE4C4 HoneyDew #F0FFF0 Silver #C0C0C0
6 DeepPink #FF1493 Orchid #DA70D6 LightCoral #F08080 Tomato #FF6347 LemonChiffon #FFFACD Lime #00FF00 PaleTurquoise #AFEEEE LightBlue #ADD8E6 NavajoWhite #FFDEAD MintCream #F5FFFA DarkGray #A9A9A9
7 PaleVioletRed #DB7093 Violet #EE82EE IndianRed #CD5C5C OrangeRed #FF4500 LightGoldenRodYellow #FAFAD2 LimeGreen #32CD32 Aquamarine #7FFFD4 PowderBlue #B0E0E6 Wheat #F5DEB3 Azure #F0FFFF DimGray #696969
8 MediumVioletRed #C71585 Fuchsia #FF00FF Crimson #DC143C PapayaWhip #FFEFD5 PaleGreen #98FB98 Turquoise #40E0D0 LightSkyBlue #87CEFA BurlyWood #DEB887 AliceBlue #F0F8FF Gray #808080
9 Magenta #FF00FF Red #FF0000 Moccasin #FFE4B5 LightGreen #90EE90 MediumTurquoise #48D1CC SkyBlue #87CEEB Tan #D2B48C GhostWhite #F8F8FF LightSlateGray #778899
10 MediumOrchid #BA55D3 FireBrick #B22222 PeachPuff #FFDAB9 MediumSpringGreen #00FA9A DarkTurquoise #00CED1 CornflowerBlue #6495ED RosyBrown #BC8F8F WhiteSmoke #F5F5F5 SlateGray #708090
11 DarkOrchid #9932CC DarkRed #8B0000 PaleGoldenRod #EEE8AA SpringGreen #00FF7F DeepSkyBlue #00BFFF SandyBrown #F4A460 SeaShell #FFF5EE DarkSlateGray #2F4F4F
12 DarkViolet #9400D3 Khaki #F0E68C MediumSeaGreen #3CB371 DodgerBlue #1E90FF GoldenRod #DAA520 Beige #F5F5DC
13 BlueViolet #8A2BE2 DarkKhaki #BDB76B SeaGreen #2E8B57 RoyalBlue #4169E1 DarkGoldenRod #B8860B OldLace #FDF5E6
14 DarkMagenta #8B008B ForestGreen #228B22 Blue #0000FF Peru #CD853F FloralWhite #FFFAF0
15 Purple #800080 Green #008000 MediumBlue #0000CD Chocolate #D2691E Ivory #FFFFF0
16 MediumPurple #9370DB DarkGreen #006400 DarkBlue #00008B Olive #808000 AntiqueWhite #FAEBD7
17 MediumSlateBlue #7B68EE YellowGreen #9ACD32 Navy #000080 SaddleBrown #8B4513 Linen #FAF0E6
18 SlateBlue #6A5ACD OliveDrab #6B8E23 MidnightBlue #191970 Sienna #A0522D LavenderBlush #FFF0F5
19 DarkSlateBlue #483D8B DarkOliveGreen #556B2F Brown #A52A2A MistyRose #FFE4E1
20 RebeccaPurple #663399 MediumAquaMarine #66CDAA Maroon #800000
21 Indigo #4B0082 DarkSeaGreen #8FBC8F
22 LightSeaGreen #20B2AA
23 DarkCyan #008B8B
24 Teal #008080

Просмотреть файл

@ -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 @@ class AnalysisExplorer:
"base0F": "#cc6633",
}
# Setup the layout
# Setup the layout
app_layout = html.Div(
[
# Top
@ -197,7 +198,9 @@ class AnalysisExplorer:
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:
@ -212,6 +215,7 @@ class AnalysisExplorer:
"text-on-image": text.TextDetector,
"objects": objects.ObjectDetector,
"summary": summary.SummaryDetector,
"colors": colors.ColorDetector,
}
# Get image ID from dropdown value, which is the filepath

195
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
}

Просмотреть файл

@ -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
}

55
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

Просмотреть файл

@ -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(None, all_options_dict, path_img_1)
analysis_explorer_objects._right_output_analysis(None, all_options_dict, path_img_2)
with pytest.raises(EnvironmentError):
analysis_explorer_faces.run_server(port=8050)

Просмотреть файл

@ -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]
}

Просмотреть файл

@ -29,6 +29,14 @@ faces module
:members:
:undoc-members:
:show-inheritance:
color_analysis module
---------------------
.. automodule:: color_analysis
:members:
:undoc-members:
:show-inheritance:
objects module
--------------

Просмотреть файл

@ -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

195
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
}

Просмотреть файл

@ -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"]
"ammico.data" = ["*.png"]
mypkg = [ "*.csv"]