Для работы с изображениями использую 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, поскольку я новичок в нем.
Я попробовал цвет [i] [j] и цвет [[i] [j]] и получил две разные ошибки: неявное преобразование массива в целое число и неопределенный метод '[] =', но теперь он просто пытается загрузить страницу и выполняет ничего такого. P.S. попытался перезапустить сервер, все то же самое - просто загружается
Помните, что return
неявно присутствует в методах Ruby, поэтому указывать его необязательно, если вы не выходите из метода раньше. Кроме того, важен отступ очень: он помогает передать структуру и намерение. Код здесь визуально перемешан, и трудно сказать, что должно быть зациклено, вложено и так далее.
Другое дело, что for
не используется в коде Ruby. Всегда есть лучший инструмент для работы. В вашем случае рассмотрите возможность использования map
для преобразования одного массива в другой. Настоящая сила Ruby - это модуль Перечислимый, и если вы не используете эти методы, вы упускаете множество полезных инструментов.
Не могли бы вы привести пример кода? @tadman
Было бы проще привести пример, если бы вы могли объяснить, что не так с вашим последним фрагментом кода. Это работает? Чего-то не хватает? Вы получаете неправильные результаты?
используя мой последний код, я получаю ошибку "undefined method` [] 'for nil: NilClass "@tadman
Проблема, с которой вы столкнулись, проистекает из того факта, что в 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