Рисование диагональных линий на изображении

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

  width = getWidth(picture)
  height = getHeight(picture)
  for x in range(0, width):
    for y in range(0, height):
      pixel = getPixel(picture, x, y)
      setColor(pixel, black)

Спасибо

3 ответа

В большинстве графических библиотек есть способ рисовать линии напрямую.

В JES есть addLine функция, чтобы вы могли сделать

addLine(picture, 0, 0, width, height)

Если вы застряли в настройке отдельных пикселей, вам следует взглянуть на алгоритм линий Брезенхэма, который является одним из наиболее эффективных алгоритмов для рисования линий.

Примечание к вашему коду: вы делаете с двумя вложенными циклами следующее

for each column in the picture
  for each row in the current column
     set the pixel in the current column and current row to black

так что в основном вы заполняете все изображение черными пикселями.

РЕДАКТИРОВАТЬ

Чтобы нарисовать несколько диагональных линий по всему изображению (оставляя пробел между ними), вы можете использовать следующий цикл

width = getWidth(picture)
height = getHeight(picture)
space = 10
for x in range(0, 2*width, space):
  addLine(picture, x, 0, x-width, height)

Это дает вам изображение вроде (пример нарисован от руки...)

диагональные линии

Это использует функциональность отсечения, предоставляемую большинством графических библиотек, т.е. части строки, которые не находятся внутри изображения, просто игнорируются. Обратите внимание, что без 2*width (т.е. если x идет только до with), будет нарисована только верхняя левая половина линий...

Я хотел бы добавить некоторые математические соображения к обсуждению...

(Просто печально, что функция addLine JES рисует только черные линии и довольно ограничена...)

Примечание. В следующем коде используетсялинейный алгоритм Брезенхэма, указанныйMartinStettner(так что спасибо ему).

Алгоритм линии Брезенхема - это алгоритм, который определяет, в каком порядке формировать близкое приближение к прямой линии между двумя заданными точками. Поскольку пиксель является атомарным объектом, линию можно нарисовать только на экране компьютера, используя какое-то приближение.

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

Код:

# The following is fast implementation and contains side effects...

import random

# Draw point, with check if the point is in the image area
def drawPoint(pic, col, x, y):
   if (x >= 0) and (x < getWidth(pic)) and (y >= 0) and (y < getHeight(pic)):
     px = getPixel(pic, x, y)
     setColor(px, col)


# Draw line segment, given two points
# From Bresenham's line algorithm
# http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
def drawLine(pic, col, x0, y0, x1, y1):

   dx = abs(x1-x0)
   dy = abs(y1-y0) 
   sx = sy = 0

   #sx = 1 if x0 < x1 else -1
   #sy = 1 if y0 < y1 else -1

   if (x0 < x1): 
     sx = 1 
   else: 
     sx = -1
   if (y0 < y1):
     sy = 1 
   else: 
     sy = -1

   err = dx - dy

   while (True):

     drawPoint(pic, col, x0, y0)

     if (x0 == x1) and (y0 == y1): 
       break

     e2 = 2 * err
     if (e2 > -dy):
       err = err - dy
       x0 = x0 + sx

     if (x0 == x1) and (y0 == y1):
       drawPoint(pic, col, x0, y0)
       break

     if (e2 <  dx):
       err = err + dx
       y0 = y0 + sy 


# Draw infinite line from segment
def drawInfiniteLine(pic, col, x0, y0, x1, y1):
   # y = m * x + b
   m = (y0-y1) / (x0-x1)
   # y0 = m * x0 + b   =>   b = y0 - m * x0
   b = y0 - m * x0

   x0 = 0
   y0 = int(m*x0 + b)
   # get a 2nd point far away from the 1st one
   x1 = getWidth(pic) 
   y1 = int(m*x1 + b)

   drawLine(pic, col, x0, y0, x1, y1)


# Draw infinite line from origin point and angle
# Angle 'theta' expressed in degres
def drawInfiniteLineA(pic, col, x, y, theta):

   # y = m * x + b
   dx = y * tan(theta * pi / 180.0)  # (need radians)
   dy = y

   if (dx == 0):
     dx += 0.000000001 # Avoid to divide by zero 

   m = dy / dx

   # y = m * x + b   =>   b = y - m * x
   b = y - m * x

   # get a 2nd point far away from the 1st one
   x1 = 2 * getWidth(pic)
   y1 = m*x1 + b

   drawInfiniteLine(pic, col, x, y, x1, y1)


# Draw multiple parallele lines, given offset and angle
def multiLines(pic, col, offset, theta, randOffset = 0):
   # Range is [-2*width, 2*width] to cover the whole surface
   for i in xrange(-2*getWidth(pic), 2*getWidth(pic), offset):
      drawInfiniteLineA(pic, col, i + random.randint(0, randOffset), 1, theta)

# Draw multiple lines, given offset, angle and angle offset
def multiLinesA(pic, col, offsetX, offsetY, theta, offsetA):
   j = 0
   # Range is [-2*width, 2*width] to cover the whole surface
   for i in xrange(-2*getWidth(pic), 2*getWidth(pic), offsetX):
      drawInfiniteLineA(pic, col, i, j, theta)
      j += offsetY
      theta += offsetA



file = pickAFile()
picture = makePicture(file)
color = makeColor(0, 65, 65) #pickAColor()
#drawline(picture, color, 10, 10, 100, 100)
#drawInfiniteLine(picture, color, 10, 10, 100, 100)
#drawInfiniteLineA(picture, color, 50, 50, 135.0)
#multiLines(picture, color, 20, 56.0)
#multiLines(picture, color, 10, 56.0, 15)
multiLinesA(picture, color, 10, 2, 1.0, 1.7) 

show(picture)


Выход (картина Пьера Сулагеса):



Надеюсь, что это дало веселье и идеи студентам JES... И другим тоже...

Где твоя picture объект приходит? Что это? Что не работает до сих пор? А какую библиотеку для доступа к изображениям вы пытаетесь использовать? (Я имею в виду, где вы получаете или намереваетесь получить "getWidth, getHeight, getPixel, setColor)?

Я думаю, что не существует библиотеки, которая дает вам "пиксель" как целый объект, который можно использовать в вызове setColor, и если это произойдет, это будет самая медленная вещь в мире - возможно, в галактике.

С другой стороны, если бы эти методы существовали и ваша картинка, код выше покрыл бы все изображение черным - вы получаете все возможные значения "y" (от 0 до высоты) внутри всех возможных значений x (от 0 до ширины).) изображения и раскраски каждого черного.

Рисование линии потребует от вас одновременного изменения x и y, например:

(используя другую "воображаемую библиотеку", но еще более правдоподобную:

for x, y in zip(range(0, width), range(0, height)):
   picture.setPixel((x,y), Black) )

Это будет своего рода работа, но линия не будет идеальной, если изображение не будет идеально квадратным, иначе будет пропускать пиксели в самом широком направлении изображения. Чтобы решить эту проблему, необходим более совершенный алгоритм, но для вас есть второй способ получить доступ к пикселям на изображении - например, с помощью библиотеки изображений Python (PIL или Pillow), Pygame или какой-либо другой библиотеки.

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