愛心代碼合集
所有代碼均來源于網(wǎng)絡(luò),若侵犯到你的利益請聯(lián)系刪除
three.js
瀏覽地址?myy.alleniverrui.top

代碼地址?https://gitee.com/alleniverrui/love
html +javascript
瀏覽地址?myy.alleniverrui.top/2

代碼地址?https://gitee.com/alleniverrui/love
c++
所需環(huán)境 easyx

#include<graphics.h>
#include <conio.h>
#include<time.h>
#include<math.h>
#include<stdlib.h>
//愛心點(diǎn)結(jié)構(gòu)體
struct Point {
double x, y;? ? ?//坐標(biāo)
COLORREF color;? //顏色
};
//顏色數(shù)組
COLORREF colors[7] = { RGB(255,32,83),RGB(252,222,250) ,RGB(255,0,0) ,RGB(255,0,0) ,RGB(255,2,2) ,RGB(255,0,8) ,RGB(255,5,5) };
//COLORREF colors[7] = { RGB(55,132,83),RGB(252,222,250) ,RGB(25,120,130) ,RGB(25,230,40) ,RGB(25,24,112) ,RGB(255,230,128) ,RGB(25,5,215) };
const int xScreen = 1200; ? //屏幕寬度
const int yScreen = 800; ? //屏幕高度
const double PI = 3.1426535159;? ? ? ? ?//圓周率
const double e = 2.71828; ? //自然數(shù)e
const double averag_distance = 0.162;? ? //弧度以0.01增長時,原始參數(shù)方程每個點(diǎn)的平均距離
const int quantity = 506; ? //一個完整愛心所需點(diǎn)的數(shù)量
const int circles = 210; ? //組成愛心主體的愛心個數(shù)(每個愛心會乘以不同系數(shù))
const int frames = 20; ? //愛心擴(kuò)張一次的幀數(shù)
Point? origin_points[quantity]; ? //創(chuàng)建一個保存原始愛心數(shù)據(jù)的數(shù)組
Point? points[circles * quantity];? ? ? //創(chuàng)建一個保存所有愛心數(shù)據(jù)的數(shù)組
IMAGE images[frames]; ? //創(chuàng)建圖片數(shù)組
//坐標(biāo)轉(zhuǎn)換函數(shù)
double screen_x(double x)
{
x += xScreen / 2;
return x;
}
//坐標(biāo)轉(zhuǎn)換函數(shù)
double screen_y(double y)
{
y = -y + yScreen / 2;
return y;
}
//創(chuàng)建x1-x2的隨機(jī)數(shù)的函數(shù)
int creat_random(int x1, int x2)
{
if (x2 > x1)
return? rand() % (x2 - x1 + 1) + x1;
else
return 0;
}
//創(chuàng)建愛心擴(kuò)張一次的全部數(shù)據(jù),并繪制成20張圖片保存
// 1 用參數(shù)方程計(jì)算出一個愛心的所有坐標(biāo)并保存在 origin_points 中
// 2 重復(fù)對 origin_points 的所有坐標(biāo)乘上不同的系數(shù)獲得一個完整的愛心坐標(biāo)數(shù)據(jù),并保存在 points 中
// 3 通過一些數(shù)學(xué)邏輯計(jì)算 points 中所有點(diǎn)擴(kuò)張后的坐標(biāo)并繪制,并覆蓋掉原來的數(shù)據(jù)(循環(huán)20次)
// 4 計(jì)算圓的外層那些閃動的點(diǎn),不保存這些點(diǎn)的數(shù)據(jù)(循環(huán)20次)
void creat_data()
{
int index = 0;
//保存相鄰的坐標(biāo)信息以便用于計(jì)算距離
double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
for (double radian = 0.1; radian <= 2 * PI; radian += 0.005)
{
//愛心的參數(shù)方程
x2 = 16 * pow(sin(radian), 3);
y2 = 13 * cos(radian) - 5 * cos(2 * radian) - 2 * cos(3 * radian) - cos(4 * radian);
//計(jì)算兩點(diǎn)之間的距離 開根號((x1-x2)平方 + (y1-y1)平方)
double distance = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
//只有當(dāng)兩點(diǎn)之間的距離大于平均距離才保存這個點(diǎn),否則跳過這個點(diǎn)
if (distance > averag_distance)
{
//x1和y1保留當(dāng)前數(shù)據(jù)
//x2和y2將在下一次迭代獲得下一個點(diǎn)的坐標(biāo)
x1 = x2, y1 = y2;
origin_points[index].x = x2;
origin_points[index++].y = y2;
}
}
index = 0;
for (double size = 0.1; size <= 20; size += 0.1)
{
//用sigmoid函數(shù)計(jì)算當(dāng)前系數(shù)的成功概率
//用個例子說明一下,假設(shè)有100個點(diǎn)成功概率為 90%,那么就可能會有90個點(diǎn)經(jīng)過篩選保留下來
// 假設(shè)有100個點(diǎn)成功概率為 20%,那么就可能會有20個點(diǎn)經(jīng)過篩選保留下來
double success_p = 1 / (1 + pow(e, 8 - size / 2));
//遍歷所有原始數(shù)據(jù)
for (int i = 0; i < quantity; ++i)
{
//用概率進(jìn)行篩選
if (success_p > creat_random(0, 100) / 100.0)
{
//從顏色數(shù)組隨機(jī)獲得一個顏色
points[index].color = colors[creat_random(0, 6)];
//對原始數(shù)據(jù)乘上系數(shù)保存在points中
points[index].x = size * origin_points[i].x + creat_random(-4, 4);
points[index++].y = size * origin_points[i].y + creat_random(-4, 4);
}
}
}
//index當(dāng)前值就是points中保存了結(jié)構(gòu)體的數(shù)量
int points_size = index;
for (int frame = 0; frame < frames; ++frame)
{
//初始化每張圖片寬xScreen,高yScreen
images[frame] = IMAGE(xScreen, yScreen);
//把第frame張圖像設(shè)為當(dāng)前工作圖片
SetWorkingImage(&images[frame]);
//計(jì)算愛心跳動的坐標(biāo)
for (index = 0; index < points_size; ++index)
{
double x = points[index].x, y = points[index].y;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //把當(dāng)前值賦值給x和y
double distance = sqrt(pow(x, 2) + pow(y, 2)); //計(jì)算當(dāng)前點(diǎn)與原點(diǎn)的距離
double diatance_increase = -0.0009 * distance * distance + 0.35714 * distance + 5; //把當(dāng)前距離代入方程獲得該點(diǎn)的增長距離
//根據(jù)增長距離計(jì)算x軸方向的增長距離 x_increase = diatance_increase * cos(當(dāng)前角度)
//cos(當(dāng)前角度)= x / distance
double x_increase = diatance_increase * x / distance / frames;
//根據(jù)增長距離計(jì)算x軸方向的增長距離 x_increase = diatance_increase * sin(當(dāng)前角度)
//sin(當(dāng)前角度)= y / distance
double y_increase = diatance_increase * y / distance / frames;
//因?yàn)橐陨嫌?jì)算得到的是一整個過程的增長距離,而整個過程持續(xù)20幀,因此要除20
//用新的數(shù)據(jù)覆蓋原來的數(shù)據(jù)
points[index].x += x_increase;
points[index].y += y_increase;
//提取當(dāng)前點(diǎn)的顏色設(shè)置為繪畫顏色
setfillcolor(points[index].color);
//注意,因?yàn)橐陨纤凶鴺?biāo)是基于數(shù)學(xué)坐標(biāo)的
//因此繪制到屏幕是就要轉(zhuǎn)換為屏幕坐標(biāo)
solidcircle(screen_x(points[index].x), screen_y(points[index].y), 1);
}
//產(chǎn)生外圍閃動的點(diǎn)
for (double size = 17; size < 23; size += 0.3)
{
for (index = 0; index < quantity; ++index)
{
//當(dāng)系數(shù)大于等于20,通過概率為百分之四十,當(dāng)系數(shù)小于20,通過概率為百分之五
//20作為關(guān)鍵值是因?yàn)閻坌闹黧w的最大系數(shù)就是20
if ((creat_random(0, 100) / 100.0 > 0.6 && size >= 20) || (size < 20 && creat_random(0, 100) / 100.0 > 0.95))
{
double x, y;
if (size >= 20)
{
//用frame的平方的正負(fù)值作為上下限并加減15產(chǎn)生隨機(jī)數(shù)
//用frame的平方的好處是frame越大,外圍閃動的點(diǎn)運(yùn)動范圍越大
x = origin_points[index].x * size + creat_random(-frame * frame / 5 - 15, frame * frame / 5 + 15);
y = origin_points[index].y * size + creat_random(-frame * frame / 5 - 15, frame * frame / 5 + 15);
}
else
{
//對于系數(shù)小于20的處理與愛心點(diǎn)一樣
x = origin_points[index].x * size + creat_random(-5, 5);
y = origin_points[index].y * size + creat_random(-5, 5);
}
//隨機(jī)獲取顏色并設(shè)置為當(dāng)前繪圖顏色
setfillcolor(colors[creat_random(0, 6)]);
//把數(shù)學(xué)坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo)再進(jìn)行繪制
solidcircle(screen_x(x), screen_y(y), 1);
//需要注意的是,我并沒有保存這些點(diǎn),因?yàn)檫@些點(diǎn)不需要前一幀的坐標(biāo)數(shù)據(jù)
//只需要當(dāng)前系數(shù)就可繪制出來,因此沒 必要保存
}
}
}
}
}
int main()
{
initgraph(xScreen, yScreen);? //創(chuàng)建屏幕
BeginBatchDraw(); ? //開始批量繪圖
srand(time(0)); ? //初始化隨機(jī)種子
creat_data(); ? //調(diào)用函數(shù)產(chǎn)生20張圖片
SetWorkingImage(); ? //調(diào)用函數(shù)把工作圖像恢復(fù)為窗口,沒有添加參數(shù)默認(rèn)為窗口
//因?yàn)榻酉率怯么翱诓シ艌D片,因此要把繪圖效果設(shè)置為窗口
bool extend = true, shrink = false;
for (int frame = 0; !_kbhit();)? ? ?//退出條件為檢測到按鍵信息
{
putimage(0, 0, &images[frame]); //播放第frame張圖片
FlushBatchDraw(); //刷新批量繪圖
Sleep(20); //延時20毫秒
cleardevice(); //清除屏幕,用來播放下一幀圖片
//注意 creat data 產(chǎn)生的只是愛心擴(kuò)張的20張圖片,并沒有產(chǎn)生愛心收縮的圖片
//但是把擴(kuò)張的圖片倒著播放就產(chǎn)生的收縮的效果
//所以下面這個 if else 語句就是決定圖片是正常播放還是倒著播放
if (extend)? //擴(kuò)張時, ++frame,正常播放
frame == 19 ? (shrink = true, extend = false) : ++frame;
else? ? ? ? ?//收縮時, --frame,倒著播放
frame == 0 ? (shrink = false, extend = true) : --frame;
}
EndBatchDraw(); //關(guān)閉批量繪圖
closegraph(); //關(guān)閉繪圖窗口
return 0; //結(jié)束程序
}
python -1

import random
from math import sin, cos, pi, log
from tkinter import *
CANVAS_WIDTH = 640? # 畫布的寬
CANVAS_HEIGHT = 480? # 畫布的高
CANVAS_CENTER_X = CANVAS_WIDTH / 2? # 畫布中心的X軸坐標(biāo)
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2? # 畫布中心的Y軸坐標(biāo)
IMAGE_ENLARGE = 11? # 放大比例
HEART_COLOR = "#ff6781"? # 心的顏色,這個是粉紅
def heart_function(t, shrink_ratio: float = IMAGE_ENLARGE):
? ? """
? ? “愛心函數(shù)生成器”
? ? :param shrink_ratio: 放大比例
? ? :param t: 參數(shù)
? ? :return: 坐標(biāo)
? ? """
? ? # 基礎(chǔ)函數(shù)
? ? x = 16 * (sin(t) ** 3)
? ? y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))
? ? # 放大
? ? x *= shrink_ratio
? ? y *= shrink_ratio
? ? # 移到畫布中央
? ? x += CANVAS_CENTER_X
? ? y += CANVAS_CENTER_Y
? ? return int(x), int(y)
def scatter_inside(x, y, beta=0.15):
? ? """
? ? 隨機(jī)內(nèi)部擴(kuò)散
? ? :param x: 原x
? ? :param y: 原y
? ? :param beta: 強(qiáng)度
? ? :return: 新坐標(biāo)
? ? """
? ? ratio_x = - beta * log(random.random())
? ? ratio_y = - beta * log(random.random())
? ? dx = ratio_x * (x - CANVAS_CENTER_X)
? ? dy = ratio_y * (y - CANVAS_CENTER_Y)
? ? return x - dx, y - dy
def shrink(x, y, ratio):
? ? """
? ? 抖動
? ? :param x: 原x
? ? :param y: 原y
? ? :param ratio: 比例
? ? :return: 新坐標(biāo)
? ? """
? ? force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6)? # 這個參數(shù)...
? ? dx = ratio * force * (x - CANVAS_CENTER_X)
? ? dy = ratio * force * (y - CANVAS_CENTER_Y)
? ? return x - dx, y - dy
def curve(p):
? ? """
? ? 自定義曲線函數(shù),調(diào)整跳動周期
? ? :param p: 參數(shù)
? ? :return: 正弦
? ? """
? ? # 可以嘗試換其他的動態(tài)函數(shù),達(dá)到更有力量的效果(貝塞爾?)
? ? return 2 * (2 * sin(4 * p)) / (2 * pi)
class Heart:
? ? """
? ? 愛心類
? ? """
? ? def __init__(self, generate_frame=20):
? ? ? ? self._points = set()? # 原始愛心坐標(biāo)集合
? ? ? ? self._edge_diffusion_points = set()? # 邊緣擴(kuò)散效果點(diǎn)坐標(biāo)集合
? ? ? ? self._center_diffusion_points = set()? # 中心擴(kuò)散效果點(diǎn)坐標(biāo)集合
? ? ? ? self.all_points = {}? # 每幀動態(tài)點(diǎn)坐標(biāo)
? ? ? ? self.build(2000)
? ? ? ? self.random_halo = 1000
? ? ? ? self.generate_frame = generate_frame
? ? ? ? for frame in range(generate_frame):
? ? ? ? ? ? self.calc(frame)
? ? def build(self, number):
? ? ? ? # 愛心
? ? ? ? for _ in range(number):
? ? ? ? ? ? t = random.uniform(0, 2 * pi)? # 隨機(jī)不到的地方造成愛心有缺口
? ? ? ? ? ? x, y = heart_function(t)
? ? ? ? ? ? self._points.add((x, y))
? ? ? ? # 愛心內(nèi)擴(kuò)散
? ? ? ? for _x, _y in list(self._points):
? ? ? ? ? ? for _ in range(3):
? ? ? ? ? ? ? ? x, y = scatter_inside(_x, _y, 0.05)
? ? ? ? ? ? ? ? self._edge_diffusion_points.add((x, y))
? ? ? ? # 愛心內(nèi)再次擴(kuò)散
? ? ? ? point_list = list(self._points)
? ? ? ? for _ in range(4000):
? ? ? ? ? ? x, y = random.choice(point_list)
? ? ? ? ? ? x, y = scatter_inside(x, y, 0.17)
? ? ? ? ? ? self._center_diffusion_points.add((x, y))
? ? @staticmethod
? ? def calc_position(x, y, ratio):
? ? ? ? # 調(diào)整縮放比例
? ? ? ? force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520)? # 魔法參數(shù)
? ? ? ? dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
? ? ? ? dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)
? ? ? ? return x - dx, y - dy
? ? def calc(self, generate_frame):
? ? ? ? ratio = 10 * curve(generate_frame / 10 * pi)? # 圓滑的周期的縮放比例
? ? ? ? halo_radius = int(4 + 6 * (1 + curve(generate_frame / 10 * pi)))
? ? ? ? halo_number = int(3000 + 4000 * abs(curve(generate_frame / 10 * pi) ** 2))
? ? ? ? all_points = []
? ? ? ? # 光環(huán)
? ? ? ? heart_halo_point = set()? # 光環(huán)的點(diǎn)坐標(biāo)集合
? ? ? ? for _ in range(halo_number):
? ? ? ? ? ? t = random.uniform(0, 2 * pi)? # 隨機(jī)不到的地方造成愛心有缺口
? ? ? ? ? ? x, y = heart_function(t, shrink_ratio=11.6)? # 魔法參數(shù)
? ? ? ? ? ? x, y = shrink(x, y, halo_radius)
? ? ? ? ? ? if (x, y) not in heart_halo_point:
? ? ? ? ? ? ? ? # 處理新的點(diǎn)
? ? ? ? ? ? ? ? heart_halo_point.add((x, y))
? ? ? ? ? ? ? ? x += random.randint(-14, 14)
? ? ? ? ? ? ? ? y += random.randint(-14, 14)
? ? ? ? ? ? ? ? size = random.choice((1, 2, 2))
? ? ? ? ? ? ? ? all_points.append((x, y, size))
? ? ? ? # 輪廓
? ? ? ? for x, y in self._points:
? ? ? ? ? ? x, y = self.calc_position(x, y, ratio)
? ? ? ? ? ? size = random.randint(1, 3)
? ? ? ? ? ? all_points.append((x, y, size))
? ? ? ? # 內(nèi)容
? ? ? ? for x, y in self._edge_diffusion_points:
? ? ? ? ? ? x, y = self.calc_position(x, y, ratio)
? ? ? ? ? ? size = random.randint(1, 2)
? ? ? ? ? ? all_points.append((x, y, size))
? ? ? ? for x, y in self._center_diffusion_points:
? ? ? ? ? ? x, y = self.calc_position(x, y, ratio)
? ? ? ? ? ? size = random.randint(1, 2)
? ? ? ? ? ? all_points.append((x, y, size))
? ? ? ? self.all_points[generate_frame] = all_points
? ? def render(self, render_canvas, render_frame):
? ? ? ? for x, y, size in self.all_points[render_frame % self.generate_frame]:
? ? ? ? ? ? render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR)
def draw(main: Tk, render_canvas: Canvas, render_heart: Heart, render_frame=0):
? ? render_canvas.delete('all')
? ? render_heart.render(render_canvas, render_frame)
? ? main.after(160, draw, main, render_canvas, render_heart, render_frame + 1)
if __name__ == '__main__':
? ? root = Tk()? # 一個Tk
? ? canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
? ? canvas.pack()
? ? heart = Heart()? # 心
? ? draw(root, canvas, heart)? # 開始畫畫~
? ? root.mainloop()
python -2
所需環(huán)境 open cv

from tkinter import *
from matplotlib import pyplot as plt
from PIL import Image
import random
import math
import numpy as np
import os
import colorsys
import CV2
from scipy.ndimage.filters import gaussian_filter
from math import sin, cos, pi, log
canvas_width = 600
canvas_height = 600
world_width = 0.05
world_heigth = 0.05
# 中間心的參數(shù)
points = None
fixed_point_size = 20000
fixed_scale_range = (4, 4.3)
min_scale = np.array([1.0, 1.0, 1.0]) * 0.9
max_scale = np.array([1.0, 1.0, 1.0]) * 0.9
min_heart_scale = -15
max_heart_scale = 16
# 外圍隨機(jī)心參數(shù)
random_point_szie = 7000
random_scale_range = (3.5, 3.9)
random_point_maxvar = 0.2
# 心算法參數(shù)
mid_point_ignore = 0.95
# 相機(jī)參數(shù)
camera_close_plane = 0.1
camera_position = np.array([0.0, -2.0, 0.0])
# 點(diǎn)的顏色
hue = 0.92
color_strength = 255
# 常用向量緩存
zero_scale = np.array([0.0, 0.0, 0.0])
unit_scale = np.array([1.0, 1.0, 1.0])
color_white = np.array([255, 255, 255])
axis_y = np.array([0.0, 1.0, 0.0])
# 渲染緩存
render_buffer = np.empty((canvas_width, canvas_height, 3), dtype=int)
strength_buffer = np.empty((canvas_width, canvas_height), dtype=float)
# 隨機(jī)點(diǎn)文件緩存
points_file = "temp.txt"
# 渲染結(jié)果
total_frames = 30
output_dir = "./output"
# 格式
image_fmt = "jpg"
def color(value):
? ? digit = list(map(str, range(10))) + list("ABCDEF")
? ? string = '#'
? ? for i in value:
? ? ? ? a1 = i // 16
? ? ? ? a2 = i % 16
? ? ? ? string += digit[a1] + digit[a2]
? ? return string
def heart_func(x, y, z, scale):
? ? bscale = scale
? ? bscale_half = bscale / 2
? ? x = x * bscale - bscale_half
? ? y = y * bscale - bscale_half
? ? z = z * bscale - bscale_half
? ? return (x ** 2 + 9 / 4 * (y ** 2) + z ** 2 - 1) ** 3 - (x ** 2) * (z ** 3) - 9 / 200 * (y ** 2) * (z ** 3)
def lerp_vector(a, b, ratio):
? ? result = a.copy()
? ? for i in range(3):
? ? ? ? result[i] = a[i] + (b[i] - a[i]) * ratio
? ? return result
def lerp_int(a, b, ratio):
? ? return (int)(a + (b - a) * ratio)
def lerp_float(a, b, ratio):
? ? return (a + (b - a) * ratio)
def distance(point):
? ? return (point[0] ** 2 + point[1] ** 2 + point[2] ** 2) ** 0.5
def dot(a, b):
? ? return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
def inside_rand(tense):
? ? x = random.random()
? ? y = -tense * math.log(x)
? ? return y
# 生成中間心
def genPoints(pointCount, heartScales):
? ? result = np.empty((pointCount, 3))
? ? index = 0
? ? while index < pointCount:
? ? ? ? # 生成隨機(jī)點(diǎn)
? ? ? ? x = random.random()
? ? ? ? y = random.random()
? ? ? ? z = random.random()
? ? ? ? # 扣掉心中間的點(diǎn)
? ? ? ? mheartValue = heart_func(x, 0.5, z, heartScales[1])
? ? ? ? mid_ignore = random.random()
? ? ? ? if mheartValue < 0 and mid_ignore < mid_point_ignore:
? ? ? ? ? ? continue
? ? ? ? heartValue = heart_func(x, y, z, heartScales[0])
? ? ? ? z_shrink = 0.01
? ? ? ? sz = z - z_shrink
? ? ? ? sheartValue = heart_func(x, y, sz, heartScales[1])
? ? ? ? # 保留在心邊上的點(diǎn)
? ? ? ? if heartValue < 0 and sheartValue > 0:
? ? ? ? ? ? result[index] = [x - 0.5, y - 0.5, z - 0.5]
? ? ? ? ? ? # 向內(nèi)擴(kuò)散
? ? ? ? ? ? len = 0.7
? ? ? ? ? ? result[index] = result[index] * (1 - len * inside_rand(0.2))
? ? ? ? ? ? # 重新賦予深度
? ? ? ? ? ? newY = random.random() - 0.5
? ? ? ? ? ? rheartValue = heart_func(result[index][0] + 0.5, newY + 0.5, result[index][2] + 0.5, heartScales[0])
? ? ? ? ? ? if rheartValue > 0:
? ? ? ? ? ? ? ? continue
? ? ? ? ? ? result[index][1] = newY
? ? ? ? ? ? # 刪掉肚臍眼
? ? ? ? ? ? dist = distance(result[index])
? ? ? ? ? ? if dist < 0.12:
? ? ? ? ? ? ? ? continue
? ? ? ? ? ? index = index + 1
? ? ? ? ? ? if index % 100 == 0:
? ? ? ? ? ? ? ? print("{ind} generated {per}%".format(ind=index, per=((index / pointCount) * 100)))
? ? return result
# 生成隨機(jī)心
def genRandPoints(pointCount, heartScales, maxVar, ratio):
? ? result = np.empty((pointCount, 3))
? ? index = 0
? ? while index < pointCount:
? ? ? ? x = random.random()
? ? ? ? y = random.random()
? ? ? ? z = random.random()
? ? ? ? mheartValue = heart_func(x, 0.5, z, heartScales[1])
? ? ? ? mid_ignore = random.random()
? ? ? ? if mheartValue < 0 and mid_ignore < mid_point_ignore:
? ? ? ? ? ? continue
? ? ? ? heartValue = heart_func(x, y, z, heartScales[0])
? ? ? ? sheartValue = heart_func(x, y, z, heartScales[1])
? ? ? ? if heartValue < 0 and sheartValue > 0:
? ? ? ? ? ? result[index] = [x - 0.5, y - 0.5, z - 0.5]
? ? ? ? ? ? dist = distance(result[index])
? ? ? ? ? ? if dist < 0.12:
? ? ? ? ? ? ? ? continue
? ? ? ? ? ? len = 0.7
? ? ? ? ? ? result[index] = result[index] * (1 - len * inside_rand(0.2))
? ? ? ? ? ? index = index + 1
? ? for i in range(pointCount):
? ? ? ? var = maxVar * ratio
? ? ? ? randScale = 1 + random.normalvariate(0, var)
? ? ? ? result[i] = result[i] * randScale
? ? return result
# 世界坐標(biāo)到相機(jī)本地坐標(biāo)
def world_2_cameraLocalSapce(world_point):
? ? new_point = world_point.copy()
? ? new_point[1] = new_point[1] + camera_position[1]
? ? return new_point
# 相機(jī)本地坐標(biāo)到相機(jī)空間坐標(biāo)
def cameraLocal_2_cameraSpace(cameraLocalPoint):
? ? depth = distance(cameraLocalPoint)
? ? cx = cameraLocalPoint[0] * (camera_close_plane / cameraLocalPoint[1])
? ? cz = -cameraLocalPoint[2] * (cx / cameraLocalPoint[0])
? ? cameraLocalPoint[0] = cx
? ? cameraLocalPoint[1] = cz
? ? return cameraLocalPoint, depth
# 相機(jī)空間坐標(biāo)到屏幕坐標(biāo)
def camerSpace_2_screenSpace(cameraSpace):
? ? x = cameraSpace[0]
? ? y = cameraSpace[1]
? ? # convert to view space
? ? centerx = canvas_width / 2
? ? centery = canvas_height / 2
? ? ratiox = canvas_width / world_width
? ? ratioy = canvas_height / world_heigth
? ? viewx = centerx + x * ratiox
? ? viewy = canvas_height - (centery + y * ratioy)
? ? cameraSpace[0] = viewx
? ? cameraSpace[1] = viewy
? ? return cameraSpace.astype(int)
# 繪制世界坐標(biāo)下的點(diǎn)
def draw_point(worldPoint):
? ? cameraLocal = world_2_cameraLocalSapce(worldPoint)
? ? cameraSpsace, depth = cameraLocal_2_cameraSpace(cameraLocal)
? ? screeSpace = camerSpace_2_screenSpace(cameraSpsace)
? ? draw_size = int(random.random() * 3 + 1)
? ? draw_on_buffer(screeSpace, depth, draw_size)
# 繪制到緩存上
def draw_on_buffer(screenPos, depth, draw_size):
? ? if draw_size == 0:
? ? ? ? return
? ? elif draw_size == 1:
? ? ? ? draw_point_on_buffer(screenPos[0], screenPos[1], color_strength, depth)
? ? elif draw_size == 2:
? ? ? ? draw_point_on_buffer(screenPos[0], screenPos[1], color_strength, depth)
? ? ? ? draw_point_on_buffer(screenPos[0] + 1, screenPos[1] + 1, color_strength, depth)
? ? elif draw_size == 3:
? ? ? ? draw_point_on_buffer(screenPos[0], screenPos[1], color_strength, depth)
? ? ? ? draw_point_on_buffer(screenPos[0] + 1, screenPos[1] + 1, color_strength, depth)
? ? ? ? draw_point_on_buffer(screenPos[0] + 1, screenPos[1], color_strength, depth)
? ? elif draw_size == 4:
? ? ? ? draw_point_on_buffer(screenPos[0], screenPos[1], color_strength, depth)
? ? ? ? draw_point_on_buffer(screenPos[0] + 1, screenPos[1], color_strength, depth)
? ? ? ? draw_point_on_buffer(screenPos[0], screenPos[1] + 1, color_strength, depth)
? ? ? ? draw_point_on_buffer(screenPos[0] + 1, screenPos[1] + 1, color_strength, depth)
# 根據(jù)色調(diào)和顏色強(qiáng)度獲取顏色
def get_color(strength):
? ? result = None
? ? if strength >= 1:
? ? ? ? result = colorsys.hsv_to_rgb(hue, 2 - strength, 1)
? ? else:
? ? ? ? result = colorsys.hsv_to_rgb(hue, 1, strength)
? ? r = min(result[0] * 256, 255)
? ? g = min(result[1] * 256, 255)
? ? b = min(result[2] * 256, 255)
? ? return np.array((r, g, b), dtype=int)
# 可以根據(jù)深度做一些好玩的
def draw_point_on_buffer(x, y, color, depth):
? ? if x < 0 or x >= canvas_width or y < 0 or y >= canvas_height:
? ? ? ? return
? ? # 混合
? ? strength = float(color) / 255
? ? strength_buffer[x, y] = strength_buffer[x, y] + strength
# 繪制緩存
def draw_buffer_on_canvas(output=None):
? ? render_buffer.fill(0)
? ? for i in range(render_buffer.shape[0]):
? ? ? ? for j in range(render_buffer.shape[1]):
? ? ? ? ? ? render_buffer[i, j] = get_color(strength_buffer[i, j])
? ? im = Image.fromarray(np.uint8(render_buffer))
? ? im = im.rotate(-90)
? ? if output is None:
? ? ? ? plt.imshow(im)
? ? ? ? plt.show()
? ? else:
? ? ? ? im.save(output)
def paint_heart(ratio, randratio, outputFile=None):
? ? global strength_buffer
? ? global render_buffer
? ? global points
? ? # 清空緩存
? ? strength_buffer.fill(0)
? ? for i in range(fixed_point_size):
? ? ? ? # 縮放
? ? ? ? point = points[i] * lerp_vector(min_scale, max_scale, ratio)
? ? ? ? # 球型場
? ? ? ? dist = distance(point)
? ? ? ? radius = 0.4
? ? ? ? sphere_scale = radius / dist
? ? ? ? point = point * lerp_float(0.9, sphere_scale, ratio * 0.3)
? ? ? ? # 繪制
? ? ? ? draw_point(point)
? ? # 生成一組隨機(jī)點(diǎn)
? ? randPoints = genRandPoints(random_point_szie, random_scale_range, random_point_maxvar, randratio)
? ? for i in range(random_point_szie):
? ? ? ? # 繪制
? ? ? ? draw_point(randPoints[i])
? ? # 高斯模糊
? ? for i in range(1):
? ? ? ? strength_buffer = gaussian_filter(strength_buffer, sigma=0.8)
? ? # 繪制緩存
? ? draw_buffer_on_canvas(outputFile)
def show_images():
? ? img = None
? ? for i in range(total_frames):
? ? ? ? save_name = "{name}.{fmt}".format(name=i, fmt=image_fmt)
? ? ? ? save_path = os.path.join(output_dir, save_name)
? ? ? ? img = CV2.imread(save_path, CV2.IMREAD_ANYCOLOR)
? ? ? ? CV2.imshow("Img", img)
? ? ? ? CV2.waitKey(25)
def gen_images():
? ? global points
? ? if not os.path.isdir(output_dir):
? ? ? ? os.mkdir(output_dir)
? ? # 嘗試加載或生成中間心
? ? if not os.path.exists(points_file):
? ? ? ? print("未發(fā)現(xiàn)緩存點(diǎn),重新生成中")
? ? ? ? points = genPoints(fixed_point_size, fixed_scale_range)
? ? ? ? np.savetxt(points_file, points)
? ? else:
? ? ? ? print("發(fā)現(xiàn)緩存文件,跳過生成")
? ? ? ? points = np.loadtxt(points_file)
? ? for i in range(total_frames):
? ? ? ? print("正在處理圖片... ", i)
? ? ? ? frame_ratio = float(i) / (total_frames - 1)
? ? ? ? frame_ratio = frame_ratio ** 2
? ? ? ? ratio = math.sin(frame_ratio * math.pi) * 0.743144
? ? ? ? randratio = math.sin(frame_ratio * math.pi * 2 + total_frames / 2)
? ? ? ? save_name = "{name}.{fmt}".format(name=i, fmt=image_fmt)
? ? ? ? save_path = os.path.join(output_dir, save_name)
? ? ? ? paint_heart(ratio, randratio, save_path)
? ? ? ? print("圖片已保存至", save_path)
if __name__ == "__main__":
? ? gen_images()
? ? while True:
? ? ? ? show_images()