绘制和着色圆形截面

时间:2018-02-09 06:45:34

标签: python

所以,我必须做一些图形/可视化工作,因为我在这个领域有0经验,这已经变成了一场噩梦。

简而言之,我有一系列同心圆(b,c,d),半径为1,2,3,垂直线(e,f)穿过原点(-x - y = 0和-x + y = 0)。以下是GeoGebra可视化:

concentric circles centered on origin with x-y axes and lines at x=y and x=-y

我还有一个包含12个灰度像素值的数组。此数组中的每个值对应于图像的一部分要着色的颜色(3个圆圈,每个圆圈有4个部分)。下面是一个示例图像,为了清晰起见,我将粉色区域着色。

enter image description here

我已经能够创建可以着色的饼图,它适用于圆圈b中的部分,但不适用于其他两部分。

from PIL import Image, ImageDraw

x_center = 400 // 2
y_center = 400 //2

img = Image.new('RGBA', (400, 400), 'white')

idraw = ImageDraw.Draw(img)

idraw.pieslice([x_center-100, x_center-100, 
               y_center + 106, y_center + 106], 225, 315, fill='blue')

enter image description here

并且用一个和弦接近了,但我需要一个弧底,而不是一条直线

from PIL import Image, ImageDraw

x_center = 400 // 2
y_center = 400 //2

im = Image.new('RGBA', (400, 400), 'white')

draw = ImageDraw.Draw(im)
draw.chord([x_center-100, x_center-100, 
           y_center + 106, y_center + 106], 225, 315, fill='blue')

enter image description here

现在,最终目标是获取最终产品并将其另存为png或jpeg。这是因为每个图像反映了一个时间片,我想将它们全部一起刷成视频。但是,我100%愿意使用最好的工具,无论是PIL,matplotlib等等(我只是对这类东西有0次经验,所以我决定使用PIL / PILLOW可能不是最聪明的。) / p>

对此事的任何见解都将深表感谢。

2 个答案:

答案 0 :(得分:1)

绘制从最大的第一个到最小的扇区序列。连续较小的圆形扇区将绘制在之前的扇形之上,从而为您寻找的区域形状。使用代码调用idraw.pieslice,例如,

idraw.pieslice([x_center-100, x_center-100, 
           y_center+100, y_center+100], 225, 315, fill='blue')
idraw.pieslice([x_center-80, x_center-80, 
           y_center+80, y_center+80], 225, 315, fill='red')

答案 1 :(得分:0)

好的,所以,在没有睡了差不多2天之后,我找到了一个解决方案,适合现在或将来也遇到这个问题的人。

简而言之,我找到了每个部分内的所有坐标,然后构建了一个位图图像。它并不是特别快,但它确实有效。

import numpy as np
from matplotlib import pyplot as plt


def inside_circle(radius, x_center, y_center):
    """
    Determines all points that fall within a circle

    Returns a set of tuples with each tuple being an x-y coordinate 
    inside the circle

    """

    valid = set()

    for x in xrange(0, 601):
        for y in xrange(0, 601):
            if ((x - x_center)*(x- x_center)) + \
               ((y - y_center)*(y - y_center)) <= radius*radius:
                valid.add((x, y))

    return valid

def above_line(all_points, p1, p2):
    """
    Determines if each point is above the line defined by p1 and p2

    Returns a set of tuples with each tuple being an x-y coordinate 
    above line

    """

    valid = set()

    for point in all_points:
        p = np.array([point])
        is_above = np.cross(p-p1, p2-p1) < 0

        if is_above:
            valid.add(tuple(point))

    return valid

# Find all points in each circle
circle_1 = inside_circle(radius=100, x_center=300, y_center=300)
circle_2 = inside_circle(radius=200, x_center=300, y_center=300)
circle_3 = inside_circle(radius=300, x_center=300, y_center=300)

# Find all points above each line
above_positive = above_line(all_points=circle_3, 
                            p1=np.array([100, 100]), 
                            p2=np.array([300, 300]))  # pos sloped line
above_negative = above_line(all_points=circle_3, 
                            p1=np.array([100, 500]), 
                            p2=np.array([300, 300]))  # neg sloped line

# Find all points in each ring
ring_1 = circle_1
ring_2 = {i for i in circle_2 if i not in circle_1}
ring_3 = {i for i in circle_3 if i not in circle_2}

# Find all points in each wedge
wedge_0 = {i for i in circle_3 if (i in above_negative) and 
          (i in above_positive)}
wedge_1 = {i for i in circle_3 if (i in above_negative) and 
          (i not in above_positive)}
wedge_2 = {i for i in circle_3 if (i not in above_negative) and 
          (i not in above_positive)}
wedge_3 = {i for i in circle_3 if (i not in above_negative) and 
          (i in above_positive)}

# Take colours and convert each value to int (my data is floats, but 
# I have used ints for this example)
image = [255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255]

for index, value in enumerate(image):
    image[index] = np.int64(round(abs(value)))

# Build a list where each index holds the coordinates for a particular 
# section [{section 0 cords} ... {section 11 cords}]
wedges = [wedge_0, wedge_1, wedge_2, wedge_3]
rings = [ring_1, ring_2, ring_3]
cords_in_sections = []
section_number = 0

for ring in rings:
    current_index = 0

    while current_index < len(wedges):
        points = {i for i in ring if i in wedges[current_index]}
        cords_in_sections.append(points)

        section_number += 1
        current_index += 1

# Create an 600x600 matrix of white pixels, then change pixel values in 
# each section
pixel_matrix = np.full((600, 600), 255)

# This is ugly, but seem to work better than a {cord: colour} dict 
for row, y in enumerate(pixel_matrix):
    for column, x in enumerate(y):
        if (column, row) in cords_in_sections[0]:
            pixel_matrix[row, column] = image[0]
        elif (column, row) in cords_in_sections[1]:
            pixel_matrix[row, column] = image[1]
        elif (column, row) in cords_in_sections[2]:
            pixel_matrix[row, column] = image[2]
        elif (column, row) in cords_in_sections[3]:
            pixel_matrix[row, column] = image[3]
        elif (column, row) in cords_in_sections[4]:
            pixel_matrix[row, column] = image[4]
        elif (column, row) in cords_in_sections[5]:
            pixel_matrix[row, column] = image[5]
        elif (column, row) in cords_in_sections[6]:
            pixel_matrix[row, column] = image[6]
        elif (column, row) in cords_in_sections[7]:
            pixel_matrix[row, column] = image[7]
        elif (column, row) in cords_in_sections[8]:
            pixel_matrix[row, column] = image[8]
        elif (column, row) in cords_in_sections[9]:
            pixel_matrix[row, column] = image[9]
        elif (column, row) in cords_in_sections[10]:
            pixel_matrix[row, column] = image[10]
        elif (column, row) in cords_in_sections[11]:
            pixel_matrix[row, column] = image[11]

plt.imshow(pixel_matrix, cmap='gray')
plt.axis('off')
plt.show()

此代码生成以下图像:

enter image description here

来自不同图像数组的另一个例子:

enter image description here