Извлечение RGB-канала изображения


22

Для данного изображения, либо в качестве входных данных (возможно, в триблетах RGB), либо с именем файла в качестве входных данных (можно предположить, что изображение имеет определенное имя файла, возможно, без расширения), выведите изображение, представляющее один цветной канал изображения.

Вы также возьмете другой вход, представляющий, какой канал вывести. Ввод может быть одним из 3 различных символов. Однако символы должны быть либо строкой, либо числом. Однако вы не можете использовать матрицу для применения к массиву в качестве входных данных. (например {1, 0, 0}, или{0, 1, 0} ).

Вы выведете <input>канал входного изображения. Вы можете сохранить его в файл или вывести набор пар RGB.

Ваша программа не должна иметь никаких ограничений на размер изображения (в РХ), и должны поддерживать либо .png, .jpg/ .jpeg/ .JPG, или RGB тройня в качестве графических форматов. (однако он может поддерживать столько, сколько вы хотите)

Прецедент:

фиолетовый оригинал

Красный канал:

фиолетовый красный

Зеленый коридор:

фиолетовый зеленый

Синий канал:

фиолетовый синий

И еще один тестовый пример, полностью красного цвета. Оригинальное фото , красный , зеленый и синий . (предупреждение: на простой и красный канал больно смотреть слишком долго)

Еще 2 теста:

Оригинальный , красный , зеленый , синий .

Оригинальный , красный , зеленый , синий .

Последние два контрольных примера взяты из изображений со всеми цветами .


Это хорошее вдохновение для языка игры в гольф, который переносит / компилирует в операции OpenCV.
Восстановить Монику - Mar--

Ответы:


2

APL (Дьялог) , 7 байт

I / O: массив триплетов RGB

⎕×⊂⎕=⍳3

Попробуйте онлайн!

⍳3 первые три целых числа

⎕= сравнить числовой ввод (выбранный канал) с этим

 заключить (таким образом, каждый триплет изображения объединяет весь этот триплет)

⎕× умножить числовой ввод (массив триплетов) с этим


12

JavaScript (ES6), 29 байт

a=>n=>a.map(b=>b.map(c=>c&n))

Ввод представляет собой двумерный массив из 24-битных целых чисел (например [[0x0000ff,0x00ff00],[0xff0000,0xffffff]]) и 16711680для красного, 65280для зеленого, 255для синего. Если это не так, попробуйте это:

JavaScript (ES6), 48 байт

a=>n=>a.map(b=>b.map(c=>c.map((d,i)=>i==n?d:0)))

Ввод представляет собой трехмерный массив значений цвета и 0для красного, 1для зеленого, 2для синего.


1
Нахальный формат ввода хаха
Конор О'Брайен,

10

Mathematica, 13 байт

ImageMultiply

Это должно быть законной версией ответа JungHwan Min. Эта функция принимает изображение и один из Red, Green, в Blueкачестве входных данных. Например:

введите описание изображения здесь

В качестве забавного факта есть также то, ColorSeparateчто дает вам отдельные каналы, но возвращает их в виде одноканальных / полутоновых изображений, так что вам все равно придется умножать их на цвет впоследствии.


Есть ли что-то, для чего у Mathematica нет встроенного?
Брайан Минтон

8

Bash + ImageMagick, 35 32 27 байт

mogrify -channel $1 -fx 0 i

Предполагает изображение в файле iи сценарий занимает один из RG, BG, BRдля синего, красного и зеленого; выводит в файл i.


бей меня к этому. Я отправил другой Баш + IM ответ ниже, с оптимизацией вы можете красть
Спарра

@Sparr Я сделал другой гольф
betseg

вы все еще можете сохранить два байта с помощью mogrify и без 'o'?
Спарр

7

Спектр , неконкурентный, 1 байт

(Не конкурирует, потому что этот вызов вдохновил этот язык.) На самом деле Spectrum - это библиотека npm с языковым интерфейсом для команд.

I

Принимает ввод как:

<filename>
channel

Назовите программу как:

cat input.txt | node spectrum.js "I"

Кроме того, вы можете предоставить информацию для подсказок:

λ node spectrum.js "I"
input> Ov3Gm.png
input> r
[ Image { 512x512 } ]

Это оставляет изображение в стеке. Для просмотра добавьте Oв конце примерно так:

λ node spectrum.js "IO"
input> Ov3Gm.png
input> r
[]

Для дополнительного удовольствия попробуйте echo filename | node spectrum.js "wO". Он выполняет все три изоляции каналов одновременно:

Уорхол


1
@ThisGuy Да, он может выполнять проверку первичности:n[d1=`[d1-P*][],.g!]#Pdd1-P~%-1=p
Конор О'Брайен,

1
@ ConorO'Brien ты видел моего тестера простоты для оператора FX ImageMagick?
Спарр

@ Спарр нет, не знаю. Ссылка?
Конор О'Брайен


7

JavaScript (ES6), 29 байт

a=>b=>a.map((v,i)=>i%3^b?0:v)

Очень похоже на ответ ETHproductions, но с более гибким вводом, чем первый метод, и меньшим, чем второй.

Это определяет функцию, которая принимает изображение как одномерный массив числовых интенсивностей цвета. Затем эта функция возвращает другую функцию, которая принимает целочисленное значение, представляющее желаемый цветовой канал.

Цвета могут быть представлены любым числовым диапазоном, если 0 указывает на полное отсутствие цвета. Например0.0 - 1.0 или0 - 255

Примеры:

Если данные изображения имеют формат RGB, то вызывается функция с аргументами (imageData)(0) вернет изображение только с красным каналом.

Если данные изображения имеют формат BGR, то вызов функции с аргументами (imageData)(2)также вернет изображение только с красным каналом.


Я думаю, i%3==b&&vтакже работает.
Нил

6

Python 2, 69 байт

from cv2 import*
def f(s,i):k=imread(s);k[:,:,[i,i-1]]=0;imwrite(s,k)

Все еще играю в гольф.

Принимает ввод как filename, n(где n0, 1 или 2). Сохраняет новое изображение поверх старого. 0зеленый, 1красный и 2синий. Спасибо @ovs, @Mikhail и @Rod за отключение байтов.


Сохранить несколько байт, понижая е и замену k[:,:,x[i][0]]=k[:,:,x[i][1]]=0сk[:,:,[1,2,0][i]]=k[:,:,i]=0
овсом

@ovs спасибо! ... На самом деле я сам только что придумал второе предложение, после того, как связался с твоим. Вы, ниндзя, подвели меня к этому.
Rɪᴋᴇʀ

Вы можете использовать, from cv2 import*чтобы сохранить несколько байтов
Род

Кажется, вы можете заменить k[:,:,i-1]=k[:,:,i]=0наk[:,:,[i,i-1]]=0
Михаил V

5

CJam , 12 байт

{3,f=f{f.*}}

Анонимный блок, который ожидает трехмерный массив RGB-триплетов и число от 0 до 2 включительно в стеке. Оставляет извлеченный массив в стеке впоследствии.

Red   -> 0
Green -> 1
Blue  -> 2

Возможно, можно играть в гольф, используя причудливый формат ввода, но я чувствую, что это немного обманывает.

Попробуйте онлайн!

Тестовый пример составлен только для демонстрации того, что использование триплетов из реального изображения было бы слишком большим.

объяснение

3,          e# The range [0 1 2]
  f=        e# Check each for equality with the RGB indicator, gives the indicator array:
            e#  [1 0 0] for 0, [0 1 0] for 1, [0 0 1] for 2
    f{      e# Map on each row of the array using the indicator array as an extra parameter
      f.*   e#  Perform vectorized multiplication of the indicator array with each triplet.
            e#   For red, multiplies red by 1, and green and blue by 0. Does similarly
            e#   for green and blue.
         }  e# (end of block)

5

PowerShell , 282 байта

$x,$y=$args;1..($a=New-Object System.Drawing.Bitmap $x).Height|%{$h=--$_;1..$a.Width|%{$i=("$($a.GetPixel(--$_,$h)|select R,G,B)"|iex)[$y];$r,$g,$b=(((0,0,$i),(0,$i,0))[$y-eq'G'],($i,0,0))[$y-eq'R'];$a.SetPixel($_,$h,[system.drawing.color]::fromargb($r,$g,$b))}};$a.save("$x$y.png")

Ничего из этого необычного «игры в гольф» или «использования встроенных модулей». Фу на это. ;-)

Здесь используется полный путь входного PNG (хотя, строго говоря, это не обязательно должен быть PNG, поскольку JPG, BMP и т. Д. Поддерживаются .NET, но я пробовал только на PNG), и один из (R, G, B)для цветного канала, затем сохраняет их в $xи $y. Затем мы создаем New-Objectтипа System.Drawing.Bitmapиз $xи магазина , что в $a.

Затем мы делаем двойной цикл по всем пикселям. Во- первых от 1до $a.Height, установка $hкаждой итерации (это нулевой индекс, так вот почему мы --$_, что экономит байткоды ( .height-1). Внутри мы рамочные от 1до $a.Width.

Каждую итерацию мы выполняем с .GetPixelопределенными w,hкоординатами, которые возвращают System.Drawing.Colorобъект. Мы selectвне R G Bих значения. iexЗдесь аккуратный трюк , который превращает это в хэш - таблице (например, что - то вроде @{R=34; G=177; B=76}) , поэтому мы можем индексировать в том , что непосредственно на нужный канал цвета [$y]. Это значение сохраняется в $i.

Далее мы устанавливаем три значения $r, $g, $bкак результат некоторых псевдо-троичных операторов, основанных на буквенном значении $y. Так, например, если $yесть R, то результат здесь есть $r=$i, $g=0, $b=0.

Затем мы .SetPixelвозвращаемся к этой конкретной w,hкоординате, создавая новую System.Drawing.Colorс использованием статики FromARGB(которая предполагает, что альфа полностью непрозрачна). Как только мы закончили цикл, мы просто .Saveдобавляем PNG в новый файл.

Примечание. Это занимает много времени, поскольку он полностью независимо проходит по каждому пикселю, выполняет несколько вычислений и вызывает каждую итерацию.

тесты:
AdmBorkBork Red AdmBorkBork Green AdmBorkBork Blue


3

Bash + ImageMagick, 41 байт

C="RGB"
mogrify -channel ${C//$1} -fx 0 x

Ввод - это файл с именем x, параметр командной строки один из RилиG илиB

Выход перезаписывает входной файл

Отличается от ответа betseg принятием более естественного однобуквенного параметра канала. Также перезаписываем вместо вывода нового файла, который бетсег может украсть :)


$1нуждается в кавычки, имена файлов могут содержать пробелы
betseg

@ betseg не совсем, я сказал, что вы можете предположить, что у него есть конкретное имя файла. Если он хочет, он может даже изменить его на чтение из имени файла xза 1 байт.
Rɪᴋᴇʀ

@Riker О, я не заметил этого, это тоже мне помогает: D
betseg

3

Чип , 78 байт

 ~Z~vS
f/F,^-.
e/E|,-Z.
d/D|>zz^.
a/AMx-x-].
b/BMx-]v-'
c/CM]v-'
 >--v'
G/gh/H

Попробуйте онлайн!

Chip - это двумерный язык, который работает с компонентными битами каждого байта в потоке байтов.

обзор

Это конкретное решение предполагает, что первый байт ввода будет управляющим символом, чтобы определить, какой канал (каналы) следует сохранить, а следующие - это байты данных изображения. Данные изображения должны быть RGB-триплетами, один байт на канал, 24 бита на пиксель:

|  1  |  2  |  3  |  4  |  5  |  6  |  7  | ... | 3n-2 |  3n  | 3n+1 |
|     |   First Pixel   |   Second Pixel  | ... |      nth Pixel     |
| Ctl | Red | Grn | Blu | Red | Grn | Blu | ... |  Red |  Grn |  Blu |

Управляющий символ интерпретируется как битовое поле, хотя только три младших бита имеют значение:

0x1  keep Red channel
0x2  keep Green channel
0x4  keep Blue channel

Это означает, что мы можем использовать символы ASCII, чтобы выбрать, какой канал мы хотим:

1означает красный
2означает синий
4означает зеленый

Или сделай что-нибудь более замысловатое

5оставить красный и синий, но не зеленый
7сохранить все каналы (изображение не изменилось)
0удалить все каналы (изображение черное)

Как это работает

Это решение довольно запутано из-за игры в гольф, но здесь идет:

  1. Прочитайте три младших бита первого байта с помощью C:B и A, и сохраните эти биты в соответствующих Mячейках памяти. Кроме того, Sподавить вывод для первого цикла.
  2. Повторяйте эти три бита. Если текущий бит включен, закройте /переключатели для вывода текущего входного байта, если он выключен, откройте переключатели, чтобы мы вывели нулевой байт.
  3. Продолжайте, пока ввод не будет исчерпан.

Просмотр результатов

Конечно, вы могли бы использовать hexdump или что-то скучное, но оказывается, что это (почти) действительно действительный формат изображения: двоичный Portable PixMap .

Просто вставьте данные изображения сверху (за исключением, конечно, управляющего байта) в файл ниже, отрегулируйте ширину / высоту, чтобы быть действительными, и вы можете просмотреть изображение в надлежащем средстве просмотра, таком как IrfanView, хотя и в более простых (как большинство браузеров). встроенные) не может справиться с этим.

P6
{width as ASCII} {height as ASCII}
255
{binary image data here}

Например (используя экранирование для необработанных данных):

P6
3 1
255
\xff\x00\x00\x00\xff\x00\x00\x00\xff

3

MATL, 21 13 байт

Yi3:iml&!*3YG

Цветовой канал должен быть определен с использованием следующего отображения: 1:red, 2:green,3:blue

Онлайн-переводчики не могут использовать imreadдля чтения изображений, поэтому здесь есть слегка измененная версия, в которой я жестко закодировал случайное изображение в источнике .

объяснение

        % Implicitly grab first input as a string (filename)
Yi      % Read the image in from a filename or URL
3:      % Push the string literal 'rgb' to the stack
i       % Grab the second input as a number
m       % Check for membership. So for example 2 will yield [false, true, false]
l&!     % Permute the dimensions to turn this 1 x 3 array into a 1 x 1 x 3 array
*       % Multiply this with the input RGB image. It will maintain the channel which
        % corresponds with the TRUE values and zero-out the channels that corresponded to
        % the FALSE values
3YG     % Display the image


2

Clojure, 421 332 байта

-89 байтов , агрессивно вставляя все, меняя старый нелепый метод удаления каналов и избавляясь от ненужного случайного импорта.

(import '(java.awt.image BufferedImage)'(clojure.lang Keyword)'(javax.imageio ImageIO)'(java.io File)'(java.awt Color))(fn[p i](doseq[y(range(.getHeight p))x(range(.getWidth p))](.setRGB p x y(.getRGB(apply #(Color. % %2 %3)(#(let[c(Color. %)](assoc [0 0 0]i(([(.getRed c)(.getGreen c)(.getBlue c)]%)i)))(.getRGB p x y))))))(ImageIO/write p"jpg"(File."./o.jpg")))

Поправил это за полчаса до начала моей смены, не зная, что я делаю. У меня мало опыта BufferedImage, так что может быть лучший способ сделать это. Я также злоупотребляю, Colorчтобы преобразовать назад и вперед между целочисленным и отдельным представлением цветов канала.

Это очень много по сравнению с другими ответами по нескольким причинам (помимо очевидного, что Clojure не является языком игры в гольф):

  • Вместо того, чтобы просто манипулировать байтовым массивом, он фактически принимает в качестве входных данных изображение, изменяет его и выводит его.

  • Я использую Java-взаимодействие, которое иногда может быть довольно многословным. Только импорт больше, чем многие ответы.

Смотрите код ниже для разбивки.

(ns bits.restrict-channel
  (:import (java.awt.image BufferedImage)
           (clojure.lang Keyword)
           (javax.imageio ImageIO)
           (java.io File)
           (java.awt Color)))

(defn restrict-channel
  "Accepts a BufferedImage and a index between 0 and 2 (inclusive).
  Removes color from all channels EXCEPT the channel indicated by color-i.
  color-i of 0 = keep red
  color-i of 1 = keep green
  color-i of 2 = keep blue"
  [^BufferedImage image ^long color-i]
  (let [; Turn a number representing RGB into a triplet representing [R G B]
        channels #(let [c (Color. %)]
                    [(.getRed c) (.getGreen c) (.getBlue c)])

        ; Create a new triplet that only contains color in the color-i channel
        zero-channels #(assoc [0 0 0] color-i ((channels %) color-i))]

    ; Loop over each pixel
    (doseq [y (range (.getHeight image))
            x (range (.getWidth image))]

      ; Grab the current color...
      (let [cur-color (.getRGB image x y)]

        ; ... setting it to stripped color triplet returned by zero-channels
        (.setRGB image x y

                          ; This "apply" part is just applying the stripped triplet to the Color constructor
                         ;  This is needed to convert the separate channels into the integer representation that `BufferedImage` uses. 

                 (.getRGB (apply #(Color. % %2 %3) (zero-channels cur-color))))))

    ; Save the result to file
    (ImageIO/write image "jpg" (File. "./o.jpg"))))

Это самая великолепная или ужасная вещь, которую я когда-либо видел. Я иду с первым.
Rɪᴋᴇʀ

@Riker Определенно первый. Я начал писать за полчаса до начала моей смены, не зная, как мне это удастся. Но это работает!
Carcigenicate

* Я на самом деле имел в виду последнее, но славные беспорядки тоже вещь.
Carcigenicate

1

Lua (love2d Framework), 498 байт

Я сделал это больше как упражнение для себя, так что оно не такое короткое, как могло бы быть (хотя я и пытался играть в гольф), но я хотел добавить его сюда, потому что я думаю, что справился хорошо. Даже если я опоздаю.

Вот код для игры в гольф, под ним - объясненная и распутанная версия.

l=love g,p,rm,bm,gm,s=l.graphics,0,1,1,1,[[uniform float m[4];vec4 effect(vec4 co,Image t,vec2 c,vec2 s){vec4 p=Texel(t,c);p.r=p.r*m[0];p.b=p.b*m[1];p.g=p.g*m[2];return p;}]]t=g.setShader h=g.newShader(s)function l.draw()h:send("m",rm,gm,bm)if p~=0 then t(h)g.draw(p)t()end end function l.filedropped(f)a=f:getFilename()p=g.newImage(f)end function l.keypressed(k)if k=="0"then rm,gm,bm=1,1,1 end if k=="1"then rm,gm,bm=1,0,0 end if k=="2"then rm,gm,bm=0,1,0 end if k=="3"then rm,gm,bm=0,0,1 end end

Вот код, в который нужно вставить файл * .jpg. После вставки изображения вы можете нажимать цифровые кнопки для красного (1) зеленого (2) или синего (3) каналов. Также, чтобы снова увидеть изображение по умолчанию, нажмите 0. На самом деле он просто показывает изображение в окне.

l=love
g=l.graphics
p=0
rm,bm,gm=1,1,1
s = [[uniform float m[4];
vec4 effect(vec4 co,Image t,vec2 c,vec2 s){vec4 p=Texel(t,c);p.r = p.r * m[0];p.b = p.b * m[1]; p.g = p.g * m[2]; return p;}
]]
sh=g.newShader(s)

function l.draw()
  sh:send("m",rm,gm,bm)
  if p~=0 then
    g.setShader(sh)
    g.draw(p)
    g.setShader()
  end
end

function l.filedropped(f)
  a=f:getFilename()
  p=g.newImage(f)
end

function l.keypressed(k)
  if k=="0"then rm,gm,bm=1,1,1 end
  if k=="1"then rm,gm,bm=1,0,0 end
  if k=="2"then rm,gm,bm=0,1,0 end
  if k=="3"then rm,gm,bm=0,0,1 end
end

Важной частью, которая выполняет всю работу, является шейдер, который является небольшим строковым объявлением в начале или не распутан:

uniform float m[4];
vec4 effect(vec4 co,Image t,vec2 c,vec2 s)
{
    vec4 p=Texel(t,c);
    p.r = p.r * m[0];
    p.b = p.b * m[1];
    p.g = p.g * m[2]; 
    return p;
}

который получает фактический пиксель изображения и просто показывает каналы по мере необходимости.

Мое тестовое изображение и различные выходы для каналов (также наверняка другие) изображение по умолчанию и изображения канала объединены


Спасибо за вашу подсказку, я исправил это, в следующий раз, когда я знаю :)
Lycea

Нет проблем! Добро пожаловать в ppcg, надеюсь, вы останетесь здесь!
Rɪᴋᴇʀ

Кроме того, вы все еще можете сыграть в гольф. Вам не нужно включать кнопки и тому подобное.
Rɪᴋᴇʀ

0

С, 60 58 байт

main(a,b)char**b;{while(scanf(b[1],&a)>0)printf("%d ",a);}

Ввод изображения представляет собой список чисел (в десятичном виде) от 0 до 255 на stdin , например

255 0 0  192 192 192  31 41 59 ...

Канал указан в качестве первого аргумента программы и является одним из

red   -> "%d%*d%*d"
green -> "%*d%d%*d"
blue  -> "%*d%*d%d"

Пример:

$ echo "255 0 0" | ./extract "%d%*d%*d"
255 
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.