276 字
1 分钟
浏览
Chem.mol PixelArt
Benzyl-titanium
/
Chem.mol-PixelArt
Waiting for api.github.com...
Waiting...
00K
0K
0K

Powered by RDKit

Image 生成 mol#

  • 白色区域不显示分子
  • 只支持一种颜色

展示#

在 pymol 中#

GitHub with PyMolTwitter with PyMol
Apple with PyMolGrok with PyMol

使用#

main.py
from rdkit import Chem, RDLogger
from rdkit.Chem import AllChem
from PIL import Image, ImageDraw, ImageOps
import numpy as np
import os
from pathlib import Path
import gc

def make_cyclobutane_art(
    input_path='input.png',
    output_mol='output.mol',
    space=4.0 # Intermolecular distance (Å, recommended 3.0-5.0)
):
    RDLogger.DisableLog('rdApp.*')

    current = Path(__file__).parent
    input_img = current / input_path
    output_mol = current / output_mol

    if not input_img.exists():
        img = Image.new('L', (64, 64), 255) # 64x64
        draw = ImageDraw.Draw(img)
        draw.rectangle((16, 16, 48, 48), outline=0, width=1)
        img.save(input_img)

    def preprocess_image(img_path):
        img = Image.open(img_path).convert('L')
        img = img.resize((64, 64), Image.NEAREST) # 64x64
        img = ImageOps.autocontrast(img)
        return np.array(img) < np.mean(img)

    pixels = preprocess_image(input_img)

    template = Chem.MolFromSmiles('C1CCC1') # cyclobutane
    template = Chem.AddHs(template)
    AllChem.EmbedMolecule(template)
    AllChem.MMFFOptimizeMolecule(template)

    mol = Chem.RWMol()
    active_pixels = np.argwhere(pixels)

    pos_list = []
    for y, x in active_pixels:
        for atom in template.GetAtoms():
            p = template.GetConformer().GetAtomPosition(atom.GetIdx())
            new_p = (x*space + p.x, (63-y)*space + p.y, p.z)
            pos_list.append(new_p)
            mol.AddAtom(atom)

    conf = Chem.Conformer(len(pos_list))
    for i, p in enumerate(pos_list):
        conf.SetAtomPosition(i, p)

    per_ring = template.GetNumAtoms()
    for i in range(0, len(pos_list), per_ring):
        if i + per_ring - 1 < len(pos_list):
            for j in range(per_ring - 1):
                mol.AddBond(i+j, i+j+1, Chem.BondType.SINGLE)
            mol.AddBond(i+per_ring-1, i, Chem.BondType.SINGLE)

    mol.AddConformer(conf)
    os.makedirs(output_mol.parent, exist_ok=True)
    Chem.MolToMolFile(mol, str(output_mol))

    del mol, template, conf
    gc.collect()
    print(f"ok")

if __name__ == "__main__":
    make_cyclobutane_art()

pip#

pip install rdkit pillow numpy

conda#

conda install -c conda-forge rdkit

结构#

├─main.py
├─input.png
└─output.mol

自定义#

space=4.0 # 分子间距 (Å, 建议 3.0-5.0)

img = img.resize((64, 64), Image.NEAREST) # 64x64

template = Chem.MolFromSmiles('C1CCC1') # 环丁烷

运行#

python main.py
Chem.mol PixelArt
https://benzyl-titanium.pages.dev/posts/art/chem_mol_pixel_art/
作者
Benzyl titanium
发布于
2025-08-16
许可协议
CC BY-NC-SA 4.0