diff --git a/bodies/body.py b/bodies/body.py index 14574143bc454df642daab03fe62d36eedd63cfd..07f31fab956f96608925d45f46e01b06f76e61ad 100644 --- a/bodies/body.py +++ b/bodies/body.py @@ -23,7 +23,7 @@ class Body(metaclass=ABCMeta): density=5e3, color=(125 / 255, 125 / 255, 125 / 255), texture=None, size_scale=1.0, distance_scale=1.0, rotation_speed=None, parent=None, ignore_mass=False, - is_fixed_star=False): + is_fixed_star=False, trail_color=None): """ 天体类 :param name: 天体名称 @@ -39,6 +39,7 @@ class Body(metaclass=ABCMeta): :param parent: 天体的父对象 :param ignore_mass: 是否忽略质量(如果为True,则不计算引力) :param is_fixed_star: 是否为恒星 + :param trail_color: 天体拖尾颜色(默认天体颜色) """ self.__his_pos = [] self.__his_vel = [] @@ -66,6 +67,7 @@ class Body(metaclass=ABCMeta): self.__rotation_speed = rotation_speed self.color = color + self.trail_color = color if trail_color is None else trail_color self.texture = texture self.size_scale = size_scale @@ -394,7 +396,7 @@ class Body(metaclass=ABCMeta): exp = v[5:] body_data[k] = eval(exp) elif isinstance(v, list): - for idx,item in enumerate(v): + for idx, item in enumerate(v): if isinstance(item, str): if item.startswith("$exp:"): exp = item[5:] diff --git a/bodies/fixed_stars/antares.py b/bodies/fixed_stars/antares.py index d03387f6a92720fd12f3e8ba08ea83cea074cc31..347fc2ad798b32fc9ac4a36ea31f7866e5ab8014 100644 --- a/bodies/fixed_stars/antares.py +++ b/bodies/fixed_stars/antares.py @@ -65,7 +65,7 @@ class Antares(FixedStar): "ignore_mass": ignore_mass } super().__init__(**params) - self.glow_num = 6 + self.glows = 6 if __name__ == '__main__': diff --git a/bodies/fixed_stars/fixed_star.py b/bodies/fixed_stars/fixed_star.py index 04da6f12f2d0dc02ba595d819a139ae222c0b3c4..e1d3b3b70699ddc41156acc0f792655419cfc3b8 100644 --- a/bodies/fixed_stars/fixed_star.py +++ b/bodies/fixed_stars/fixed_star.py @@ -27,10 +27,12 @@ class FixedStar(Body): init_velocity=[0, 0, 0], color=(0xFF, 0xFF, 0xFF), texture=None, size_scale=1.0, distance_scale=1.0, - rotation_speed=0.1, ignore_mass=False, density=1.408e3): + rotation_speed=0.1, ignore_mass=False, density=1.408e3, trail_color=None, + texture_bright=None, texture_contrast=None): if texture is None or texture == "fixed_star.png": self.color = color - texture = self.gen_texture(texture) + # bright=1.1, contrast=3.2 + texture = self.gen_texture(texture, texture_bright, texture_contrast) params = { "name": name, "mass": mass, @@ -42,13 +44,14 @@ class FixedStar(Body): "size_scale": size_scale, "distance_scale": distance_scale, "rotation_speed": rotation_speed, - "ignore_mass": ignore_mass + "ignore_mass": ignore_mass, + "trail_color": trail_color } super().__init__(**params) self.light_on = True - self.glow_num = 10 + self.glows = 10 - def gen_texture(self, texture): + def gen_texture(self, texture, texture_bright, texture_contrast): if texture is None: return None texture_path = find_texture_root_path() @@ -59,7 +62,11 @@ class FixedStar(Body): if os.path.exists(save_file): return save_file fixed_star_img = os.path.join(texture_path, texture) - gen_fixed_star_texture(self.color, save_file=save_file, fixed_star_img=fixed_star_img) + gen_fixed_star_texture(self.color, + bright=texture_bright, + contrast=texture_contrast, + save_file=save_file, + fixed_star_img=fixed_star_img) return save_file @property diff --git a/bodies/fixed_stars/rigel.py b/bodies/fixed_stars/rigel.py index 3c9820bbe2744fdf836e47a47e4b74305ebbf869..d26361f330509857e01ebced1ad8bacbbb6b14d6 100644 --- a/bodies/fixed_stars/rigel.py +++ b/bodies/fixed_stars/rigel.py @@ -56,7 +56,7 @@ class Rigel(FixedStar): "ignore_mass": ignore_mass } super().__init__(**params) - self.glow_num = 7 + self.glows = 7 if __name__ == '__main__': diff --git a/bodies/fixed_stars/stephenson_2_18.py b/bodies/fixed_stars/stephenson_2_18.py index f2556a3928f84424ee0805bc0dda8da6dc42dc66..d48ee4467243ae297f8d1292469fcfdf9d310a35 100644 --- a/bodies/fixed_stars/stephenson_2_18.py +++ b/bodies/fixed_stars/stephenson_2_18.py @@ -48,7 +48,7 @@ class Stephenson_2_18(FixedStar): def __init__(self, name="史蒂文森2-18", mass=14.28e5 * MO, init_position=[0, 0, 0], init_velocity=[0, 0, 0], - color=((198,29,3)), + color=(198, 29, 3), texture="fixed_star.png", size_scale=1.0, distance_scale=1.0, rotation_speed=0.1, ignore_mass=False): params = { @@ -62,16 +62,19 @@ class Stephenson_2_18(FixedStar): "size_scale": size_scale, "distance_scale": distance_scale, "rotation_speed": rotation_speed, - "ignore_mass": ignore_mass + "ignore_mass": ignore_mass, + "texture_bright": 3, + "texture_contrast": 4 } super().__init__(**params) - self.glow_num = 5 + self.glows = (12, 1.008, 0.1) if __name__ == '__main__': from bodies import Sun + fixed_star = Stephenson_2_18() sun = Sun() print(fixed_star) print("质量倍数", fixed_star.mass / sun.mass) - print("半径倍数", fixed_star.raduis / sun.raduis) \ No newline at end of file + print("半径倍数", fixed_star.raduis / sun.raduis) diff --git a/bodies/sun.py b/bodies/sun.py index d5e77b87b5b537e8fec18e09aaa94237fda90a6c..589077f36c21e6dc258f6bd852f15a2762c1f38b 100644 --- a/bodies/sun.py +++ b/bodies/sun.py @@ -23,7 +23,7 @@ class Sun(FixedStar): init_velocity=[0, 0, 0], color=(170, 98, 25), texture="sun2.jpg", size_scale=1.0, distance_scale=1.0, - rotation_speed=0.6130, ignore_mass=False): + rotation_speed=0.6130, ignore_mass=False, trail_color=None): params = { "name": name, "mass": mass, @@ -35,7 +35,8 @@ class Sun(FixedStar): "size_scale": size_scale, "distance_scale": distance_scale, "rotation_speed": rotation_speed, - "ignore_mass": ignore_mass + "ignore_mass": ignore_mass, + "trail_color": trail_color } super().__init__(**params) diff --git a/common/image_utils.py b/common/image_utils.py index 7726f5f1776eac897b9835ec0991855cc2f2866f..1e40748b3c835562e6fe4abca6452ffd7c850f8c 100644 --- a/common/image_utils.py +++ b/common/image_utils.py @@ -6,8 +6,117 @@ # link :https://gitcode.net/pythoncr/ # python_version :3.8 # ============================================================================== -from PIL import Image, ImageColor +from PIL import Image, ImageColor, ImageEnhance, ImageStat +import math import os +import numpy as np +import colorsys + +rgb_to_hsv = np.vectorize(colorsys.rgb_to_hsv) +hsv_to_rgb = np.vectorize(colorsys.hsv_to_rgb) + + +def image_file_enhance(imageFilePath, bright, contrast, color, sharpness, saveFolderPath): + """ + 图像增强之亮度、对比度与饱和度调整 + :param imageFilePath: 图像文件路径 + :param bright: 亮度 + :param contrast: 对比度 + :param color: 饱和度 + :param sharpness: 清晰度 + :param saveFolderPath: 结果保存路径 + :return: + """ + imageFileName = os.path.basename(imageFilePath) + imageOriginal = Image.open(imageFilePath) + # 亮度调整 + brightEnhancer = ImageEnhance.Brightness(imageOriginal) + imageBright = brightEnhancer.enhance(bright) + imageBrightFileName = "Bright-%0.2f_" % bright + imageFileName + imageBrightFilePath = os.path.join(saveFolderPath, imageBrightFileName) + imageBright.save(imageBrightFilePath) + # 对比度调整 + contrastEnhancer = ImageEnhance.Contrast(imageOriginal) + imageContrast = contrastEnhancer.enhance(contrast) + imageContrastFileName = "Contrast-%0.2f_" % contrast + imageFileName + imageContrastFilePath = os.path.join(saveFolderPath, imageContrastFileName) + imageContrast.save(imageContrastFilePath) + # 饱和度调整 + colorEnhancer = ImageEnhance.Color(imageOriginal) + imageColor = colorEnhancer.enhance(color) + imageColorFileName = "Color-%0.2f_" % color + imageFileName + imageColorFilePath = os.path.join(saveFolderPath, imageColorFileName) + imageColor.save(imageColorFilePath) + # 清晰度调整 + SharpnessEnhancer = ImageEnhance.Sharpness(imageOriginal) + imageSharpness = SharpnessEnhancer.enhance(sharpness) + imageSharpnessFileName = "Sharpness-%0.2f_" % sharpness + imageFileName + imageSharpnessFilePath = os.path.join(saveFolderPath, imageSharpnessFileName) + imageSharpness.save(imageSharpnessFilePath) + return + + +def image_enhance(imageOriginal, bright=0, contrast=0, color=0, sharpness=0): + """ + 图像增强之亮度、对比度与饱和度调整 + :param imageFilePath: 图像文件路径 + :param bright: 亮度 + :param contrast: 对比度 + :param color: 饱和度 + :param sharpness: 清晰度 + :param saveFolderPath: 结果保存路径 + :return: + """ + image = imageOriginal + if bright > 0: + # 亮度调整 + brightEnhancer = ImageEnhance.Brightness(image) + image = brightEnhancer.enhance(bright) + + if contrast > 0: + # 对比度调整 + contrastEnhancer = ImageEnhance.Contrast(image) + image = contrastEnhancer.enhance(contrast) + + if color > 0: + # 饱和度调整 + colorEnhancer = ImageEnhance.Color(image) + image = colorEnhancer.enhance(color) + + if sharpness > 0: + # 清晰度调整 + SharpnessEnhancer = ImageEnhance.Sharpness(image) + image = SharpnessEnhancer.enhance(sharpness) + + return image + + +def shift_hue(arr, hout): + r, g, b, a = np.rollaxis(arr, axis=-1) + h, s, v = rgb_to_hsv(r, g, b) + h = hout + r, g, b = hsv_to_rgb(h, s, v) + arr = np.dstack((r, g, b, a)) + return arr + + +def colorize_color(src_image, color): + h, s, v = rgb_to_hsv(*color) + # img_hsv = src_image.convert('HSV') + return colorize(src_image, h * 255) + + +def colorize(src_image, hue): + """ + Colorize PIL image `original` with the given + `hue` (hue within 0-360); returns another PIL image. + """ + img = Image.open(src_image) + img = img.convert('RGBA') + arr = np.array(np.asarray(img).astype('float')) + new_img = Image.fromarray(shift_hue(arr, hue / 360.).astype('uint8'), 'RGBA') + + return new_img # 图片背景透明化 @@ -37,13 +146,6 @@ def mix(img1, img2, coordinator=(0, 0)): return out -# verse = transPNG("") -# -# mix("file", verse).save('xxx.png', 'PNG') -# -# -# from PIL import Image - def create_image(width, height, color): """ 创建指定大小和背景颜色的图片对象 @@ -92,15 +194,232 @@ def find_texture(texture): return "" -def gen_fixed_star_texture(color, save_file, fixed_star_img="fixed_star.png"): +def gen_fixed_star_texture(color, save_file, fixed_star_img="fixed_star.png", bright=None, contrast=None): + bright = 1.1 if bright is None else bright + contrast = 3.2 if contrast is None else contrast fixed_star_img = find_texture(fixed_star_img) if fixed_star_img is None: err_msg = "未找到纹理图片:" % fixed_star_img raise Exception(err_msg) trans_img = trans_png(fixed_star_img) bg_img = create_image(trans_img.width, trans_img.height, color) - mix(bg_img, trans_img).save(save_file, 'PNG') + mixed = mix(bg_img, trans_img) + mixed = image_enhance(mixed, bright=bright, contrast=contrast) + mixed.save(save_file, 'PNG') + return mixed + + +def gray_to_mono(gray_img, color_val): + """ + 将灰度图片转为单色图片,颜色值为 color_val + + 参数: + gray_img: 灰度图片,PIL Image对象 + color_val: 单色值,RGB颜色值的元组,例如(255, 0, 0)表示红色 + + 返回值: + 单色图片,PIL Image对象 + """ + # 创建一个白色图片,用于后续的alpha通道处理 + white_img = Image.new('RGB', gray_img.size, (255, 255, 255)) + + # 将灰度图片转换为单色图片 + mono_img = gray_img.convert('L').convert('RGBA') + + # 用单色值替换灰色部分 + for y in range(mono_img.height): + for x in range(mono_img.width): + r, g, b, a = mono_img.getpixel((x, y)) + if r == g == b: + # 灰度颜色值范围:0~255 + gray_val = r + # 将灰度值映射到颜色值范围内 + color_r = int((gray_val / 255) * color_val[0]) + color_g = int((gray_val / 255) * color_val[1]) + color_b = int((gray_val / 255) * color_val[2]) + mono_img.putpixel((x, y), (color_r, color_g, color_b, a)) + + # 将白色部分替换回去 + alpha_img = white_img.convert('RGBA') + alpha_img.paste(mono_img, (0, 0), mono_img) + return alpha_img if __name__ == '__main__': - gen_fixed_star_texture((100, 100, 255), "xxx.png") + # gray_img = Image.open("../textures/fixed_star.png") + # mono = gray_to_mono(gray_img, (0, 0, 255)).show() + # image_enhance(mono,bright=1,contrast=2).show() + + gen_fixed_star_texture((198, 29, 3), "xxx.png",bright=2.2,contrast=3).show() + + # fixed_star_img = find_texture("sun.png") + # colorize_color(fixed_star_img,(0,0xff,0xff)).show() + +# def brightness(src_img): +# if isinstance(src_img, str): +# im = Image.open(src_img) +# else: +# im = src_img +# im = im.convert('L') +# stat = ImageStat.Stat(im) +# return stat.mean[0] +# +# +# def brightness(src_img): +# if isinstance(src_img, str): +# im = Image.open(src_img) +# else: +# im = src_img +# im = im.convert('L') +# stat = ImageStat.Stat(im) +# return stat.rms[0] +# +# +# def brightness(src_img): +# if isinstance(src_img, str): +# im = Image.open(src_img) +# else: +# im = src_img +# stat = ImageStat.Stat(im) +# r, g, b = stat.mean +# return math.sqrt(0.241 * (r ** 2) + 0.691 * (g ** 2) + 0.068 * (b ** 2)) +# +# +# def brightness(src_img): +# if isinstance(src_img, str): +# im = Image.open(src_img) +# else: +# im = src_img +# stat = ImageStat.Stat(im) +# r, g, b = stat.rms +# return math.sqrt(0.241 * (r ** 2) + 0.691 * (g ** 2) + 0.068 * (b ** 2)) + + +# def brightness(src_img): +# if isinstance(src_img, str): +# im = Image.open(src_img) +# else: +# im = src_img +# stat = ImageStat.Stat(im) +# gs = (math.sqrt(0.241 * (r ** 2) + 0.691 * (g ** 2) + 0.068 * (b ** 2)) for r, g, b in im.getdata()) +# return sum(gs) / stat.count[0] + +# +# +# def auto_adjust_contrast_brightness_xxx(src_img): +# """ +# 自适应地调整图片的对比度和亮度。 +# +# :param image_path: 图像路径。 +# :return: 调整后的图像对象。 +# """ +# if isinstance(src_img, str): +# image = Image.open(src_img) +# else: +# image = src_img +# # 打开图像文件 +# # image = Image.open(image_path) +# +# # 获取图像直方图 +# histogram = image.histogram() +# +# # 计算直方图的最小和最大值 +# min_value, max_value = 0, 255 +# for i in range(256): +# if histogram[i] > 0: +# min_value = i +# break +# for i in range(255, -1, -1): +# if histogram[i] > 0: +# max_value = i +# break +# +# # 计算调整参数 +# mid_value = 127.5 +# contrast_factor = 127.5 / (max_value - min_value) +# brightness_factor = mid_value - contrast_factor * (min_value + max_value) / 2 +# +# # 调整对比度和亮度 +# contrast_enhancer = ImageEnhance.Contrast(image) +# contrast_image = contrast_enhancer.enhance(contrast_factor) +# brightness_enhancer = ImageEnhance.Brightness(contrast_image) +# brightness_image = brightness_enhancer.enhance(brightness_factor) +# +# return brightness_image +# +# +# +# def auto_adjust_contrast_brightness333(src_img): +# """ +# 自适应地调整图片的对比度和亮度。 +# +# :param image_path: 图像路径。 +# :return: 调整后的图像对象。 +# """ +# if isinstance(src_img, str): +# image = Image.open(src_img) +# else: +# image = src_img +# +# # 计算图像平均亮度 +# brightness = 0 +# pixels = image.load() +# width, height = image.size +# for x in range(width): +# for y in range(height): +# r, g, b = pixels[x, y] +# brightness += 0.299 * r + 0.587 * g + 0.114 * b +# brightness /= width * height +# +# # 计算调整参数 +# mid_value = 127.5 +# contrast_factor = mid_value / brightness +# brightness_factor = mid_value - brightness * contrast_factor +# +# # 调整对比度和亮度 +# contrast_enhancer = ImageEnhance.Contrast(image) +# contrast_image = contrast_enhancer.enhance(contrast_factor) +# brightness_enhancer = ImageEnhance.Brightness(contrast_image) +# brightness_image = brightness_enhancer.enhance(brightness_factor) +# +# return brightness_image +# +# +# def auto_adjust_contrast_brightness(src_img): +# """ +# 自适应地调整图片的对比度和亮度。 +# +# :param image_path: 图像路径。 +# :return: 调整后的图像对象。 +# """ +# if isinstance(src_img, str): +# image = Image.open(src_img) +# else: +# image = src_img +# +# # 获取图像直方图 +# histogram = image.histogram() +# +# # 计算直方图的最小和最大值 +# min_value, max_value = 0, 255 +# for i in range(256): +# if histogram[i] > 0: +# min_value = i +# break +# for i in range(255, -1, -1): +# if histogram[i] > 0: +# max_value = i +# break +# +# # 计算调整参数 +# mid_value = 127.5 +# contrast_factor = mid_value / (max_value - min_value) +# brightness_factor = mid_value - contrast_factor * (min_value + max_value) / 2 +# +# # 调整对比度和亮度 +# contrast_enhancer = ImageEnhance.Contrast(image) +# contrast_image = contrast_enhancer.enhance(contrast_factor) +# brightness_enhancer = ImageEnhance.Brightness(contrast_image) +# brightness_image = brightness_enhancer.enhance(brightness_factor) +# +# return brightness_image diff --git a/scenes/fixed_stars.py b/scenes/fixed_stars.py index a5724d46c427eac4f2ab8dda9c70a4b5c5fa709e..f1ec440abe63489341d64f03ce26567c460cc131 100644 --- a/scenes/fixed_stars.py +++ b/scenes/fixed_stars.py @@ -31,7 +31,7 @@ if __name__ == '__main__': ] distance_sum = 0 for idx, body in enumerate(bodies): - body.rotation_speed /= 50 + body.rotation_speed /= 10 if idx > 1: body.light_on = False # 关闭灯光效果,只有太阳对地球有灯光效果 d = pow((body.diameter + bodies[idx - 1].diameter) * SIZE_SCALE, 0.75) * 120 diff --git a/scenes/tri_bodies_sim_perfect.py b/scenes/tri_bodies_sim_perfect.py index 83a5fa1fc4035744861a7dc096b7711cbef49423..6d07abcd3abc09d4cc67520e36af0de68def9778 100644 --- a/scenes/tri_bodies_sim_perfect.py +++ b/scenes/tri_bodies_sim_perfect.py @@ -31,17 +31,17 @@ if __name__ == '__main__': Sun(name="红轨太阳A", mass=mass, init_position=[0, math.sqrt(3) * r, 0], init_velocity=[-p, 0, 0], - color=(255, 0, 0), + trail_color=(255, 0, 0), size_scale=5e1, texture="sun2.jpg"), # 太阳放大 100 倍 Sun(name="绿轨太阳B", mass=mass, init_position=[-r, 0, 0], init_velocity=[1 / 2 * p, -math.sqrt(3) / 2 * p, 0], - color=(0, 255, 0), + trail_color=(0, 255, 0), size_scale=5e1, texture="sun2.jpg"), # 太阳放大 100 倍 Sun(name="蓝轨太阳C", mass=mass, init_position=[r, 0, 0], init_velocity=[1 / 2 * p, math.sqrt(3) / 2 * p, 0], - color=(0, 0, 255), + trail_color=(0, 0, 255), size_scale=5e1, texture="sun2.jpg"), # 太阳放大 100 倍 # Earth(init_position=[0, -349597870.700, 0], # init_velocity=[15.50, 0, 0], diff --git a/simulators/views/ursina_view.py b/simulators/views/ursina_view.py index 573362779f10bdcb25987576ac56ba3c95764e35..62a75c9db173b19c4f7a0b5a55f8b546041fe93d 100644 --- a/simulators/views/ursina_view.py +++ b/simulators/views/ursina_view.py @@ -117,7 +117,8 @@ class Planet(Entity): texture=texture, color=self.plant_color, position=pos, - rotation=rotation # ,double_sided=True + rotation=rotation, + double_sided=True ) if hasattr(self.body_view.body, "torus_stars") or \ @@ -142,7 +143,7 @@ class Planet(Entity): self.trails = {} # 根据天体的颜色获取拖尾的颜色 - trail_color = conv_to_vec4_color(self.body_view.body.color) + trail_color = conv_to_vec4_color(self.body_view.body.trail_color) trail_color = adjust_brightness(trail_color, 0.4) self.trail_color = color.rgba(trail_color[0], trail_color[1], trail_color[2], 0.6) # 拖尾球体的大小为该天体的 1/5 @@ -297,26 +298,35 @@ class Planet(Entity): # lights = [] # # 创建多个新的 Entity 对象,作为光晕的容器 # _color = color.rgba(1.0, 0.6, 0.2, 1) - if hasattr(self.body_view.body, "glow_num"): - glow_num = self.body_view.body.glow_num - if glow_num > 12: - glow_num = 12 - if glow_num > 5: - alpha = 0.1 - elif glow_num > 4: - alpha = 0.2 - elif glow_num > 3: - alpha = 0.3 - elif glow_num > 2: - alpha = 0.4 - - if glow_num > 0: - # _color = color.white - _color = self.body_view.body.color - _color = color.rgba(_color[0]/255, _color[1]/255, _color[2]/255, 1) - for i in range(glow_num): - glow_entity = Entity(parent=self, model='sphere', color=_color, - scale=math.pow(1.03, i+1), alpha=alpha) + if hasattr(self.body_view.body, "glows"): + # glows = (glow_num:10, glow_scale:1.03 glow_alpha:0.1~1) + glows = self.body_view.body.glows + if glows is not None: + if isinstance(glows, tuple): + if len(glows) == 3: + glow_num, glow_scale, glow_alpha = glows + elif len(glows) == 2: + glow_num, glow_scale = glows + glow_alpha = None + else: + glow_num = glows + glow_scale = 1.02 + glow_alpha = None + + if glow_num > 0: + glow_alphas = [0, 0.5, 0.4, 0.3, 0.2, 0.1] + if glow_alpha is None: + if glow_num < len(glow_alphas)-1: + glow_alpha = glow_alphas[glow_num] + else: + glow_alpha = glow_alphas[-1] + + # _color = color.white + _color = self.body_view.body.color + _color = color.rgba(_color[0]/255, _color[1]/255, _color[2]/255, 1) + for i in range(glow_num): + glow_entity = Entity(parent=self, model='sphere', color=_color, + scale=math.pow(glow_scale, i+1), alpha=glow_alpha) if hasattr(self.body_view.body, "light_on"): if self.body_view.body.light_on: for i in range(2):