Сохранение цвета пикселя в массиве Ruby

Для работы с изображениями использую CarrierWave и MiniMagick. Я загружаю изображение. Прямо сейчас мне нужно получить значения всех пикселей изображения и сохранить их в массиве

Если я использую следующий код, он работает хорошо

def pixelcolor 
@image = MiniMagick::Image.open(image.path)     
return @image.get_pixels[56][34][1] # 56 and 34 - random numbers for row and column
end

следующий код тоже работает

def pixelcolor 
@image = MiniMagick::Image.open(image.path)     
width = @image.width
color = Array.new   
for i in 0..width
  color[i] = i
end
return color
end

Но если я попытаюсь выполнить следующий код, он не сработает

def pixelcolor 
@image = MiniMagick::Image.open(image.path)     
width = @image.width
color = Array.new
for i in 0..width
    color[i] = @image.get_pixels[45][65][0]
end
return color
end

В результате мне нужно что-то вроде этого

def pixelcolor 
@image = MiniMagick::Image.open(image.path)     
width = @image.width
height = @image.height  
red = Array.new  
green = Array.new
blue = Array.new    
for i in 0..width
    for j in 0..height
      red[i][j] = @image.get_pixels[width][height][0]
      green[i][j] = @image.get_pixels[width][height][1]
      blue[i][j] = @image.get_pixels[width][height][2]
    end
end
return red, green, blue
end

Много времени назад я создал очень похожий проект на C++ для работы с изображениями, поэтому я знаю, что делать, но не уверен, как это сделать правильно в Ruby, поскольку я новичок в нем.

"не работает" - уточните, пожалуйста. Получаете ошибку или неожиданный результат?
Stefan 02.05.2018 01:23

Я попробовал цвет [i] [j] и цвет [[i] [j]] и получил две разные ошибки: неявное преобразование массива в целое число и неопределенный метод '[] =', но теперь он просто пытается загрузить страницу и выполняет ничего такого. P.S. попытался перезапустить сервер, все то же самое - просто загружается

Димон Клименко 02.05.2018 01:29

Помните, что return неявно присутствует в методах Ruby, поэтому указывать его необязательно, если вы не выходите из метода раньше. Кроме того, важен отступ очень: он помогает передать структуру и намерение. Код здесь визуально перемешан, и трудно сказать, что должно быть зациклено, вложено и так далее.

tadman 02.05.2018 01:53

Другое дело, что for не используется в коде Ruby. Всегда есть лучший инструмент для работы. В вашем случае рассмотрите возможность использования map для преобразования одного массива в другой. Настоящая сила Ruby - это модуль Перечислимый, и если вы не используете эти методы, вы упускаете множество полезных инструментов.

tadman 02.05.2018 01:55

Не могли бы вы привести пример кода? @tadman

Димон Клименко 02.05.2018 02:10

Было бы проще привести пример, если бы вы могли объяснить, что не так с вашим последним фрагментом кода. Это работает? Чего-то не хватает? Вы получаете неправильные результаты?

tadman 02.05.2018 02:11

используя мой последний код, я получаю ошибку "undefined method` [] 'for nil: NilClass "@tadman

Димон Клименко 02.05.2018 02:20
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
2
7
171
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема, с которой вы столкнулись, проистекает из того факта, что в Ruby нет концепции «многомерных массивов», отдельные массивы всегда одномерные.

Однако вы можете иметь массивы вложенный, которые представляют собой массивы, содержащие массивы, такие как [[], [], []].


Давайте посмотрим на два конкретных места:

red = Array.new # Note: this could as well be `red = []`

Итак, вы присвоили red единственный пустой массив. Хорошо. Вот что вы сделаете позже:

red[i][j] = ...

Остальная часть линии нам даже не нужна, она уже явно сломана.

На самой первой итерации red по-прежнему пустой массив. Таким образом, red[i] - это nil, поскольку внутри абсолютно ничего нет. nil не имеет средств доступа к массиву ([] и []=), поэтому вы будете получать ошибки при попытке чтения или записи в него, как если бы это был массив.

Итак, вам нужно, чтобы red[i] был фактический массив, чтобы вы могли помещать в него данные. Сделаем это.

Поскольку вы заранее знаете размер ваших массивов, вы можете просто выделить и сразу же заполнить red массивами соответствующей длины:

red = Array.new(width) { Array.new(height) }

Например, для width = 2 и height = 3 вот результат, который вы получите:

[
  [nil, nil, nil],
  [nil, nil, nil]
]

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

См. документы для Array.new для различных способов создания массива.


Осторожный:

Я не зря использовал "блочную" форму Array.new.

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

red = Array.new(width, Array.new(height))

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


Боковое примечание: вы, вероятно, захотите поменять местами width и height по размерам, поскольку в графических программах обычно используются массивы ряды, а не столбцы. Хотя зависит. Может не повлиять на вашу конкретную проблему.

Большое спасибо! Похоже, я лучше разбирался в массивах в Ruby @ D-side

Димон Клименко 02.05.2018 19:56

Другие вопросы по теме