Середній колір зображення


21

Середній колір зображення

Вчені змогли визначити середній колір Всесвіту, але в скільки байтів ми можемо знайти середній колір на зображенні?

Ваше завдання

Вашим входом буде одне зображення, яке вам знадобиться знайти середнє значення кольорів на зображенні та вивести шістнадцятковий кольоровий рядок ( #??????). Зображення може бути будь-якого з наступних форматів

  • JPEG / JFIF
    • JPEG 2000
  • TIFF
  • GIF
  • BMP
  • PNG
  • ПНМ
    • PPM

Вхід також може сприйматися як URL / URI до зображення.

Вбудовані функції, які обчислюють середні показники або вибирають зображення одразу, такі, ImageMeasurementsякі не дозволені.

Приклади

Результати дещо відрізнятимуться в залежності від того, як ви обчислюєте середню кількість і які кольорові моделі ви використовуєте. Я додав значення RGB та LCH (HSV) для зображень нижче.

Зразок 1вихід: #53715FRGB, також може бути #3B7D3DLCH (HSV)


Зразок 2вихід: #8B7D41RGB, #96753CLCH (HSV)


З якими форматами зображень ми маємо оброблятись? Зокрема, чи можемо ми обробляти лише PPM?
Денніс

Чи можу я мати менший тестовий випадок, будь ласка? Мій сценарій дуже повільний, і, хоча я буду виконувати його у великих випадках, я не витрачаю цей час, якщо він неправильний. Або навіть просто сценарій, з яким ви його обчислили.
Мальтісен

@Maltysen Я додав приклад 240x140. Будемо сподіватися, що це досить мало
Downgoat

Чи завжди ми повинні округлювати? У першому прикладі, 95.6...яке ви округлили 95у вказаному виході.
Денніс

4
PS Немає сенсу публікувати запитання у пісочниці, якщо ви не збираєтесь залишати його там принаймні на 24 години, щоб люди в інших часових поясах могли бачити його, і реально вам потрібно приділити йому 72 години, оскільки не всі перевіряють пісочниця нав’язливо.
Пітер Тейлор

Відповіді:


19

Pyth - 23 22 19 18 16 байт

Транспортує, щоб отримати всі канали, потім підсумовує, ділить і гексифікує кожен. Закінчується об'єднанням і попередньою а #.

+\#sm.H/sdldCs'z

Знімає ім'я файлу зображення (будь-якого типу) з stdin та виводить у stdout. ДУЖЕ ПОЛІ .

+               String concat
 \#             "#"
 s              String concat all channels
 m              Map
  .H            Hex string
    /  ld       Divided by length of channel
     sd         Sum of channel
  C             Transpose to separate into channels
   s            Concatenate all rows
    'z          Read image with filename input

Вибірка зразка

>>>pyth avg.pyth 
V5VAR.jpg
#8b7d41

Ви можете вказати тип зображення, якщо такий є.
isaacg

1
@isaacg хороший момент. Це займає що завгодно.
Мальтісен

Як це потрібно, чи розшифровує jpeg до растрової карти?
Alec Teal

3
@AlecTeal Відповідно до документації, Pyth перевіряє, чи файл є зображенням, і автоматично перетворює його в растрову карту. За допомогою пошуку у сховищі GitHub схоже, що він використовує PILбібліотеку для обробки зображень. Подивіться тут для точного джерела.
Бакуріу

@Bakuriu - Я не підтримав цю відповідь, тому що я не знав, як Pyth обробляє зображення, так що це виглядало на мене трохи рибно ... але тепер, коли ти дав зрозуміти там, це отримує мій голос. Дякуємо за роз’яснення!
rayryeng

22

Баш, 46 байт

ImageMagick масштабує зображення до одного пікселя, який містить середнє значення кольорів на зображенні, а потім виводить його як текст.

convert $1 -scale 1x1\! txt:-|egrep -o '#\w+'

4
Це розумно! +1
Мальтісен

10

MATLAB - 68 байт

Зображення зчитується imreadразом із тим, uigetfileщоб відкрити графічний інтерфейс для вибору зображення, яке потрібно завантажити. Припущення цього коду полягає в тому, що всі зображення є RGB, а для обчислення середнього кольору підсумовуємо кожен канал окремо, а потім ділимо на стільки елементів, скільки є в одному каналі, яка є загальною кількістю пікселів у RGB-зображенні ( ), розділеною на 3. Оскільки середнє можливо, можливо, генерує значення з плаваючою комою, потрібно зателефонувати до округлення числа до нуля . у поєднанні з шістнадцятковим рядком форматування ( ) використовується для друку кожного цілого значення в середньому в його шістнадцятковий еквівалент. Однак є можливість гарантувати, що додатковий 0 вкладений ліворуч, якщо середнє значення для будь-якого каналу буде менше 16numel(I)fixsprintf%x02* .

I=imread(uigetfile);
['#' sprintf('%02x',fix(sum(sum(I))*3/numel(I)))]

Зразок виконання

Приємно в тому imread, що ви можете читати зображення безпосередньо з URL-адрес. В якості відтворюваного прикладу, припустимо, ви завантажили зображення на свій комп’ютер і запустили вищевказаний код ... але для демонстрації я прочитаю зображення прямо з Code Golf:

Перше зображення

>> I=imread('http://i.stack.imgur.com/dkShg.jpg');
>> ['#' sprintf('%02x',fix(sum(sum(I))*3/numel(I)))]

ans =

#53715f

Друге зображення

>> I=imread('http://i.stack.imgur.com/V5VAR.jpg');
>> ['#' sprintf('%02x',fix(sum(sum(I))*3/numel(I)))]

ans =

#8b7d41

* Примітка. Це були спільні зусилля, які доклали користувачі StackOverflow в чаті MATLAB та Octave .


7

CJam, 27 байт

'#[q~]5>3/_:.+\,f/"%02X"fe%

Це читає зображення PPM від STDIN.

CJam не має вбудованої обробки зображень, тому цей код очікує ASCII Portable PixMap (магічне число P3) з повною 24-бітовою палітрою (максимальне значення 255) і без коментарів.

Тестовий запуск

$ cjam avg.cjam < dkShg.ppm 
#53715F

Як це працює

'#     e# Push that character.
[q~]   e# Evaluate the input and collect the results in an array.
5>     e# Discard the first first results (Pi, 3, width, height, range).
3/     e# Split into chunks of length 3 (RGB).
_:.+   e# Push a copy and add across the columns (RGB).
\,f/   e# Divide each sum by the length of the array (number of pixels).
"%02X" e# Push that format string (hexadecimal integer, zero-pad to two digits).
fe%    e# Format each integer, using the format string.

7

HTML5 + JavaScript (ES6), 335 байт

Це не збирається перемагати, але мені було весело робити це все одно.

Використовує HTML5 Canvas API . Введення - URL-адреса зображення, що підтримується CORS .

f=(u,i=new Image)=>{i.crossOrigin='';i.src=u;i.onload=e=>{x=(c=document.createElement('canvas')).getContext('2d');a=w=c.width=i.width;a*=h=c.height=i.height;x.drawImage(i,0,0);for(d=x.getImageData(m=0,0,w,h).data,r=[0,0,0];m<d.length;m+=4){r[0]+=d[m];r[1]+=d[m+1];r[2]+=d[m+2]}console.log('#'+r.map(v=>(~~(v/a)).toString(16)).join``)}}

Демо

Оскільки це ES6, він наразі працює лише у Firefox та Edge.

f = (u,i = new Image) => {
  i.crossOrigin = '';
  i.src = u;
  i.onload = e => {
    x = (c = document.createElement('canvas')).getContext('2d');
    a = w = c.width = i.width;
    a *= h = c.height = i.height;
    x.drawImage(i, 0, 0);
    for (d = x.getImageData(m = 0, 0, w, h).data, r = [0, 0, 0]; m < d.length; m += 4) {
      r[0] += d[m]
      r[1] += d[m + 1];
      r[2] += d[m + 2];
    }
    console.log('#' + r.map(v => (~~(v/a)).toString(16)).join``)
  }
}

// Snippet stuff
console.log = x => document.body.innerHTML += x + '<br>';

f('http://crossorigin.me/https://i.stack.imgur.com/dkShg.jpg');

f('http://crossorigin.me/https://i.stack.imgur.com/V5VAR.jpg');


3
Гей, мені подобається, що це можна виконати безпосередньо у вашій відповіді, оскільки це HTML + JS :) +1.
rayryeng

Ви не можете замінити new Imageїх Image()?
Ісмаїл Мігель

@IsmaelMiguelTypeError: Constructor Image requires 'new'
rink.attendant.6

Лайно. Але ви можете створити W='width'і H='height'використовувати i[H]абоi[W]
Ісмаель Мігель

1
@IsmaelMiguel Для використання більше символів
rink.attendant.6

6

Python [3] + SciPy, 144 133 121

Завантажує піксельні дані, суми для кожного каналу, ділиться на розмір *, формати. Значення округляються до нуля.

* розмір = ширина * висота * каналів, таким чином множиться на 3

from scipy import misc,sum
i=misc.imread(input())
print('#'+(3*'{:2x}').format(*sum(i.astype(int),axis=(0,1))*3//i.size))

1
Чому б не використовувати input()для проходження шляху? Це заощадить 20 байт.
Каде

Спасибі! Однак мені вдалося зберегти 11 байт.
Транг Оул

Вам потрібно тільки один імпорт, import scipy. Змінити m.imreadна misc.imread.
Каде

Чи не працюю без імпорту різних, NameError: name 'misc' is not defined. Спробував from scipy import*, теж не працює.
Транг Оул

2
@TrangOul Про що from scipy import sum, misc as m? Ви заощаджуєте і тоді, коли використовуєте суму.
matsjoyce

3

R, 90 байт

rgb(matrix(apply(png::readPNG(scan(,"")),3,function(x)sum(x*255)%/%length(x)),nc=3),m=255)

Шлях до файлу PNG зчитується з STDIN. Пакетpng потрібно встановити.

Крок за кроком:

#Reads path from stdin and feeds it to function readPNG from package png
p = png::readPNG(scan(,""))
#The result is a 3d matrix (1 layer for each color channel) filled with [0,1] values
#So next step, we compute the mean on each layer using apply(X,3,FUN)
#after moving the value to range [0,255] and keeping it as an integer.
a = apply(p,3,function(x)sum(x*255)%/%length(x))
#The result is then moved to a matrix of 3 columns:
m = matrix(a, nc=3)
#Which we feed to function rgb, while specifying that we're working on range [0,255]
rgb(m, m=255)

# Example:
rgb(matrix(apply(png::readPNG(scan(,"")),3,function(x)sum(x*255)%/%length(x)),nc=3),m=255)
# 1: ~/Desktop/dkShg.png
# 2: 
# Read 1 item
# [1] "#53715F"

2

C, 259 байт

Знімає файл PPM без коментарів .

double*f,r,g,b;x,y,z,i;char*s="%d %d %d";main(a,_){(a-2)?(feof(f)?0:(fscanf(f,s,&x,&y,&z),r+=(x-r)/i,g+=(y-g)/i,b+=(z-b)/i++,main(0,0))):(f=fopen(((char**)_)[1],"r"),fscanf(f,"%*s%*d%*d%*d"),r=g=b=0.,i=1,main(0,0),printf(s,(int)r,(int)g,(int)b),fclose(f));}

Процес

Початковий код:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE *f = fopen(argv[1],"r");
    int w,h,d,x,y,z,i;
    double r,g,b;
    fscanf(f,"%*s %d %d %d",&w,&h,&d);//get width, height, depth, ignore P6
    r = g = b = 0.0; //zero r, g, and b totals
    for (i=1; i<=w*h; ++i) {
        fscanf(f,"%d %d %d",&x,&y,&z);//get next pixel
        r+=(x-r)/i;//update averages
        g+=(y-g)/i;
        b+=(z-b)/i;
    }
    printf("%d %d %d",(int)r,(int)g,(int)b);//print result
    fclose(f);
    return 0;
}

Обріжте змінні та видаліть цикл:

double r,g,b;
FILE *f;
int i;
int main(int argc, char *argv[])
{
    if (argc==2) { // {./me} {file.ppm}
        f = fopen(argv[1],"r");
        fscanf(f,"%*s%*d%*d%*d");//drop info
        r = g = b = 0.0;
        i = 1;
        main(0,0);//begin load loop
        printf("%d %d %d",(int)r,(int)g,(int)b);
        fclose(f)
    } else {
        if (feof(f)) return 0;
        fscanf(f,"%d%d%d",&x,&y,&z);
        r+=(x-r)/i;
        g+=(y-g)/i;
        b+=(z-b)/i;
        i++;
        main(0,0);
    }
    return 0;
}

Звідти я поєднав різні твердження в одну заяву повернення. Вилучили її та будь-яку іншу інформацію про сторонній тип, перейменували змінні та вирізали пробіл.


2

Кобра - 371

@ref 'System.Numerics'
use System.Drawing
use System.Numerics
class P
    def main
        i,d=Bitmap(Console.readLine?''),BigInteger
        r,g,b,c=d(),d(),d(),d()
        for x in i.width,for y in i.height,r,g,b,c=for n in 4 get BigInteger.add([r,g,b,c][n],d([(p=i.getPixel(x,y)).r,p.g,p.b,1][n]))
        print'#'+(for k in[r,g,b]get Convert.toString(BigInteger.divide(k,c)to int,16)).join('')

2

Java, 449 447 446 430 426 байт

import java.awt.*;interface A{static void main(String[]a)throws Exception{java.awt.image.BufferedImage i=javax.imageio.ImageIO.read(new java.io.File(new java.util.Scanner(System.in).nextLine()));int r=0,g=0,b=0,k=0,x,y;for(x=0;x<i.getWidth();x++)for(y=0;y<i.getHeight();k++){Color c=new Color(i.getRGB(x,y++));r+=c.getRed();g+=c.getGreen();b+=c.getBlue();}System.out.printf("#%06X",0xFFFFFF&new Color(r/k,g/k,b/k).getRGB());}}

Завдяки цій відповіді на переповнення стека за String.formatтрюк.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.