8000 Improve color indexing · Issue #7 · photoprism/photoprism · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Improve color indexing #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
3 of 5 tasks
lastzero opened this issue Oct 8, 2018 · 19 comments
Closed
3 of 5 tasks

Improve color indexing #7

lastzero opened this issue Oct 8, 2018 · 19 comments
Assignees
Labels
enhancement Enhancement or improvement of an existing feature help wanted Help with this would be much appreciated!
Milestone

Comments

@lastzero
Copy link
Member
lastzero commented Oct 8, 2018

As a user, I want to search for color names so that I can find matching photos.

The color indexing implemented right now is just a proof-of-concept. It finds too many different colors (with complicated names). We need to reimplement indexing using another algorithm like k-means and use a reduced list of colors: red, pink, purple, indigo, blue, cyan, teal, green, lime, yellow, amber, orange, brown, grey, white and black.

Acceptance Criteria:

  • You SHOULD use the k-means clustering algorithm (unless you find a better method)
  • You MAY use any open-source Go libraries as long as the license is compatible with GPL
  • The following dominant colors MUST be detected: red, pink, purple, indigo, blue, cyan, teal, green, lime, yellow, amber, orange, brown, grey, white and black - color codes see Material Design palette
  • Only colors.go and related tests MUST be changed (you don't need to touch the indexer etc)
  • You MAY add "light" or "dark" as color name prefix, to indicate if it's light or dark
@lastzero lastzero added idea Feedback wanted / feature request good first issue help wanted Help with this would be much appreciated! labels Oct 8, 2018
@lastzero
Copy link
Member Author
8000

Source files:

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.

@darkLord19
Copy link

I am interested in contributing to this project. Can you please give some starting points to solve this issue?

@lastzero
Copy link
Member Author

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

@darkLord19
Copy link

@lastzero This sounds interesting. I will work on this. If I have any questions, I'll ask here.

@lastzero
Copy link
Member Author

Thank you! Please post a proposal (containing algorithm, colors, performance,...) before you invest lots of time coding on a specific solution :)

@jkomyno
Copy link
jkomyno commented Oct 18, 2018

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.

@lastzero
Copy link
Member Author

@jkomyno Yes, that looks great. Of course with the material color names (or similar simple ones). Nobody wants to search for "peachpuff", I guess.

@jkomyno
Copy link
jkomyno commented Oct 18, 2018

@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",
    "70
8000
0": "#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"
}

@lastzero
Copy link
Member Author

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.

@jkomyno
Copy link
jkomyno commented Oct 18, 2018

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

@lastzero
Copy link
Member Author

Best data structure probably is a map mapping unique color codes to (not unique) color names.

@lastzero lastzero added help wanted Help with this would be much appreciated! enhancement Enhancement or improvement of an existing feature and removed help wanted Help with this would be much appreciated! good first issue idea Feedback wanted / feature request labels Nov 13, 2018
@lastzero lastzero added this to the MVP milestone Nov 17, 2018
@lastzero
Copy link
Member Author

@jkomyno Still working on this? I will set the issue to "in-progress" then. We are not in a hurry, just asking.

@IssueHuntBot
Copy link

@lastzero has funded $20.00 to this issue. See it on IssueHunt

@lastzero lastzero changed the title Improved color indexing Improve color indexing Dec 20, 2018
@IssueHuntBot
Copy link

@issuehuntfest has funded $20.00 to this issue. See it on IssueHunt

@skunert
Copy link
Contributor
skunert commented Feb 15, 2019

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?

@evanoberholster
Copy link

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?

@lastzero
Copy link
Member Author
lastzero commented Apr 9, 2019

@evanoberholster Yes, but not sure why I haven't used it initially. prominentcolor can certainly serve as inspiration.

lastzero added a commit that referenced this issue Apr 26, 2019
Other implementations were unstable due to the use of random numbers.
This seems to be fast and also enables us to search specific parts
of an image. 16 colors are indexed (Material Design).
@lastzero
Copy link
Member Author

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!

Screenshot 2019-04-26 at 02 30 23

@IssueHuntBot
Copy link

@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

lastzero added a commit that referenced this issue May 4, 2019
Images are scaled down to ~331px. Filenames contain object and color.
lastzero added a commit that referenced this issue May 4, 2019
Since we're not using the very same colors as material design anymore,
MaterialColor was renamed to IndexedColor.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhancement or improvement of an existing feature help wanted Help with this would be much appreciated!
Projects
None yet
Development

No branches or pull requests

7 participants
0