Comments (19)
May I propose a solution using something like Palitra? It is usable both as a library and as a CLI tool.
It allows to restrict the number of colours returned and the possible colours are the ones defined with a name by the CSS3 specification. This is similar to @lastzero proposal to use Material Design Palette's colours spec.
from photoprism.
@lastzero This sounds interesting. I will work on this. If I have any questions, I'll ask here.
from photoprism.
@jkomyno Yes, that looks great. Of course with the material color names (or similar simple ones). Nobody wants to search for "peachpuff", I guess.
from photoprism.
Source files:
- https://github.com/photoprism/photoprism/blob/develop/internal/photoprism/colors.go
- https://github.com/photoprism/photoprism/blob/develop/internal/photoprism/colors_test.go
Right now we're using the "github.com/RobCherry/vibrant" library, but I feel this is not what we want for a search. We want the human impression of the image. Let's say max 2 or 3 colors from the material design color palette.
from photoprism.
I am interested in contributing to this project. Can you please give some starting points to solve this issue?
from photoprism.
@darkLord19 It's not really something to fix, like a bug (except the panics this library causes).
If you look at the models / database tables and the indexer, you'll see that colors are being indexed, so that you can search for them. So now, we want the search to return good results. That means you want a defined, short list of colors you can search for (right now it's like 128 different colors). Also you want those colors to have something to do with the human perception of the image. Requires some research an experiments. I think it's fun. Just not straight forward.
from photoprism.
Thank you! Please post a proposal (containing algorithm, colors, performance,...) before you invest lots of time coding on a specific solution :)
from photoprism.
@lastzero Lol for the "peachpuff" example. I came up with a script to download the latest Material Design color spec as a JSON. It may be further normalized and processed to obtain a structure similar to this one.
The crawler script:
// Go to https://material.io/design/color/the-color-system.html#tools-for-picking-colors,
// open the Chrome console and run the following:
function getColors() {
const elements = document.querySelectorAll('#tools-for-picking-colors .color-tag:first-child');
return [].reduce.call(elements, (acc, color) => {
const compositeShadeName = color.getElementsByClassName('shade')[0].textContent;
const splitCompositeShadeName = compositeShadeName.split(' ');
if (splitCompositeShadeName.length === 1) {
// it's either black or white
acc['black'] = '#000';
acc['white'] = '#FFF';
} else {
const shadeName = compositeShadeName.split(' ').slice(0, -1).join(' ').toLowerCase();
const colorVariants = color.parentNode.querySelectorAll('.color-tag:not(:first-child)');
acc[shadeName] = [].reduce.call(colorVariants, (accVariant, colorVariant) => {
const shade = colorVariant.getElementsByClassName('shade')[0].textContent;
const hex = colorVariant.getElementsByClassName('hex')[0].textContent;
accVariant[shade] = hex;
return accVariant;
}, {});
}
return acc;
}, {});
}
The result:
JSON.stringify(getColors(), null, 2);
{
"red": {
"100": "#FFCDD2",
"200": "#EF9A9A",
"300": "#E57373",
"400": "#EF5350",
"500": "#F44336",
"600": "#E53935",
"700": "#D32F2F",
"800": "#C62828",
"900": "#B71C1C",
"A100": "#FF8A80",
"A200": "#FF5252",
"A400": "#FF1744",
"A700": "#D50000"
},
"pink": {
"100": "#F8BBD0",
"200": "#F48FB1",
"300": "#F06292",
"400": "#EC407A",
"500": "#E91E63",
"600": "#D81B60",
"700": "#C2185B",
"800": "#AD1457",
"900": "#880E4F",
"A100": "#FF80AB",
"A200": "#FF4081",
"A400": "#F50057",
"A700": "#C51162"
},
"purple": {
"100": "#E1BEE7",
"200": "#CE93D8",
"300": "#BA68C8",
"400": "#AB47BC",
"500": "#9C27B0",
"600": "#8E24AA",
"700": "#7B1FA2",
"800": "#6A1B9A",
"900": "#4A148C",
"A100": "#EA80FC",
"A200": "#E040FB",
"A400": "#D500F9",
"A700": "#AA00FF"
},
"deep purple": {
"100": "#D1C4E9",
"200": "#B39DDB",
"300": "#9575CD",
"400": "#7E57C2",
"500": "#673AB7",
"600": "#5E35B1",
"700": "#512DA8",
"800": "#4527A0",
"900": "#311B92",
"A100": "#B388FF",
"A200": "#7C4DFF",
"A400": "#651FFF",
"A700": "#6200EA"
},
"indigo": {
"100": "#C5CAE9",
"200": "#9FA8DA",
"300": "#7986CB",
"400": "#5C6BC0",
"500": "#3F51B5",
"600": "#3949AB",
"700": "#303F9F",
"800": "#283593",
"900": "#1A237E",
"A100": "#8C9EFF",
"A200": "#536DFE",
"A400": "#3D5AFE",
"A700": "#304FFE"
},
"blue": {
"100": "#BBDEFB",
"200": "#90CAF9",
"300": "#64B5F6",
"400": "#42A5F5",
"500": "#2196F3",
"600": "#1E88E5",
"700": "#1976D2",
"800": "#1565C0",
"900": "#0D47A1",
"A100": "#82B1FF",
"A200": "#448AFF",
"A400": "#2979FF",
"A700": "#2962FF"
},
"light blue": {
"100": "#B3E5FC",
"200": "#81D4FA",
"300": "#4FC3F7",
"400": "#29B6F6",
"500": "#03A9F4",
"600": "#039BE5",
"700": "#0288D1",
"800": "#0277BD",
"900": "#01579B",
"A100": "#80D8FF",
"A200": "#40C4FF",
"A400": "#00B0FF",
"A700": "#0091EA"
},
"cyan": {
"100": "#B2EBF2",
"200": "#80DEEA",
"300": "#4DD0E1",
"400": "#26C6DA",
"500": "#00BCD4",
"600": "#00ACC1",
"700": "#0097A7",
"800": "#00838F",
"900": "#006064",
"A100": "#84FFFF",
"A200": "#18FFFF",
"A400": "#00E5FF",
"A700": "#00B8D4"
},
"teal": {
"100": "#B2DFDB",
"200": "#80CBC4",
"300": "#4DB6AC",
"400": "#26A69A",
"500": "#009688",
"600": "#00897B",
"700": "#00796B",
"800": "#00695C",
"900": "#004D40",
"A100": "#A7FFEB",
"A200": "#64FFDA",
"A400": "#1DE9B6",
"A700": "#00BFA5"
},
"green": {
"100": "#C8E6C9",
"200": "#A5D6A7",
"300": "#81C784",
"400": "#66BB6A",
"500": "#4CAF50",
"600": "#43A047",
"700": "#388E3C",
"800": "#2E7D32",
"900": "#1B5E20",
"A100": "#B9F6CA",
"A200": "#69F0AE",
"A400": "#00E676",
"A700": "#00C853"
},
"light green": {
"100": "#DCEDC8",
"200": "#C5E1A5",
"300": "#AED581",
"400": "#9CCC65",
"500": "#8BC34A",
"600": "#7CB342",
"700": "#689F38",
"800": "#558B2F",
"900": "#33691E",
"A100": "#CCFF90",
"A200": "#B2FF59",
"A400": "#76FF03",
"A700": "#64DD17"
},
"lime": {
"100": "#F0F4C3",
"200": "#E6EE9C",
"300": "#DCE775",
"400": "#D4E157",
"500": "#CDDC39",
"600": "#C0CA33",
"700": "#AFB42B",
"800": "#9E9D24",
"900": "#827717",
"A100": "#F4FF81",
"A200": "#EEFF41",
"A400": "#C6FF00",
"A700": "#AEEA00"
},
"yellow": {
"100": "#FFF9C4",
"200": "#FFF59D",
"300": "#FFF176",
"400": "#FFEE58",
"500": "#FFEB3B",
"600": "#FDD835",
"700": "#FBC02D",
"800": "#F9A825",
"900": "#F57F17",
"A100": "#FFFF8D",
"A200": "#FFFF00",
"A400": "#FFEA00",
"A700": "#FFD600"
},
"amber": {
"100": "#FFECB3",
"200": "#FFE082",
"300": "#FFD54F",
"400": "#FFCA28",
"500": "#FFC107",
"600": "#FFB300",
"700": "#FFA000",
"800": "#FF8F00",
"900": "#FF6F00",
"A100": "#FFE57F",
"A200": "#FFD740",
"A400": "#FFC400",
"A700": "#FFAB00"
},
"orange": {
"100": "#FFE0B2",
"200": "#FFCC80",
"300": "#FFB74D",
"400": "#FFA726",
"500": "#FF9800",
"600": "#FB8C00",
"700": "#F57C00",
"800": "#EF6C00",
"900": "#E65100",
"A100": "#FFD180",
"A200": "#FFAB40",
"A400": "#FF9100",
"A700": "#FF6D00"
},
"deep orange": {
"100": "#FFCCBC",
"200": "#FFAB91",
"300": "#FF8A65",
"400": "#FF7043",
"500": "#FF5722",
"600": "#F4511E",
"700": "#E64A19",
"800": "#D84315",
"900": "#BF360C",
"A100": "#FF9E80",
"A200": "#FF6E40",
"A400": "#FF3D00",
"A700": "#DD2C00"
},
"brown": {
"100": "#D7CCC8",
"200": "#BCAAA4",
"300": "#A1887F",
"400": "#8D6E63",
"500": "#795548",
"600": "#6D4C41",
"700": "#5D4037",
"800": "#4E342E",
"900": "#3E2723"
},
"gray": {
"100": "#F5F5F5",
"200": "#EEEEEE",
"300": "#E0E0E0",
"400": "#BDBDBD",
"500": "#9E9E9E",
"600": "#757575",
"700": "#616161",
"800": "#424242",
"900": "#212121"
},
"blue gray": {
"100": "#CFD8DC",
"200": "#B0BEC5",
"300": "#90A4AE",
"400": "#78909C",
"500": "#607D8B",
"600": "#546E7A",
"700": "#455A64",
"800": "#37474F",
"900": "#263238"
},
"black": "#000",
"white": "#FFF"
}
from photoprism.
Ah, I meant just the names! The variant doesn't matter. I would use a simple lookup table (like it is implemented now), but loading a custom table from an external json / yaml file might also be an idea. We only use yaml for config at the moment.
from photoprism.
The variant doesn't matter
Do you mean that you would only select the colors with, let's say, the 500
variant?
That would produce the following:
{
"white": "#FFF",
"black": "#000",
"red": "#F44336",
"pink": "#E91E63",
"purple": "#9C27B0",
"deep purple": "#673AB7",
"indigo": "#3F51B5",
"blue": "#2196F3",
"light blue": "#03A9F4",
"cyan": "#00BCD4",
"teal": "#009688",
"green": "#4CAF50",
"light green": "#8BC34A",
"lime": "#CDDC39",
"yellow": "#FFEB3B",
"amber": "#FFC107",
"orange": "#FF9800",
"deep orange": "#FF5722",
"brown": "#795548",
"gray": "#9E9E9E",
"blue gray": "#607D8B"
}
from photoprism.
Best data structure probably is a map mapping unique color codes to (not unique) color names.
from photoprism.
@jkomyno Still working on this? I will set the issue to "in-progress" then. We are not in a hurry, just asking.
from photoprism.
@lastzero has funded $20.00 to this issue. See it on IssueHunt
from photoprism.
@issuehuntfest has funded $20.00 to this issue. See it on IssueHunt
from photoprism.
Hey, I am interested in picking up this issue. However, I am not sure I can follow the discussion here.
Right now, the vibrant library extracts colors from the picture. Then we compute the distance to the colors from the colornames library (which is responsible for the complicated names). So if I would define a new map only containing the colors you describe in the original post, wouldn't that solve the problem already? Why should we reimplement K-Means for this?
from photoprism.
Has anyone taken a look at: EdlinOrg/prominentcolor. It's based off of k-means and can be adjusted todo what was described above.
Instead of indexing via known color names, you could index based on Nearest-Neighbor search. Any thoughts on this?
from photoprism.
@evanoberholster Yes, but not sure why I haven't used it initially. prominentcolor
can certainly serve as inspiration.
from photoprism.
I've just pushed an implementation that doesn't use random numbers. It also enables us to search specific parts of an image (3x3 pixels = up to 9 colors). Seems to work well for now!
from photoprism.
@lastzero has rewarded $36.00 to @skunert. See it on IssueHunt
- 💰 Total deposit: $40.00
- 🎉 Repository reward(0%): $0.00
- 🔧 Service fee(10%): $4.00
from photoprism.
Related Issues (20)
- Indexed Image Names Differ From Original File Names
- Index: Create a new photo or find an existing one if the photo UID has been restored from a sidecar YAML file HOT 1
- Library: Live photo / video preview loading delay (1-2 seconds)
- Video: Allow streaming of all HEVC videos under Windows, e.g. by transcoding to AVC HOT 4
- WebDAV: Adding TrueNAS as a service for syncing files does not work HOT 2
- Idea: As a User, I would like to see the current upload speed of the file being uploaded in the iOS/Android app
- Support for Cryptomator FS under Windows HOT 1
- Setup: Provide ARMv7 installation packages HOT 1
- Develop: Upgrade base image to Ubuntu 24.04 LTS (Noble Numbat)
- task "convert" takes a very long time to sort through the already encoded files HOT 1
- Picture Handling: Use Archive to conveniently manage second priority pictures
- Docker Photoprism error after server reboot
- Stacks: Stack files by dc:identifier HOT 1
- UX : Add Favorites section to main navigation for users with role viewer
- Metadata: Support reading GPS information from xmp HOT 2
- Frontend: Direct Link to images in frontend HOT 1
- Docker Compose: Rename `docker-compose.yml` to `compose.yaml`
- Account: Allow Users to Manage App Passwords from the UI HOT 7
- HEIC: Support spatial images as used for Apple Vision Pro HOT 2
- Index: Skip JPEG files with a ".heic" extension HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from photoprism.