How can I update a GLB/GLTF 3D model texture in Python - python

I want to load a GLB model in Python, replace the existing texture with another texture image and save it.
So far I can load, modify and export the model. Also, I found a way to append a local image to the model.
But I'm not sure how to find and replace the existing texture.
Example 3D model with one texture file: https://modelviewer.dev/shared-assets/models/Astronaut.glb
from pygltflib import GLTF2
from pygltflib.utils import ImageFormat, Image
filename = "Astronaut.glb"
gltf = GLTF2().load(filename)
image = Image()
image.uri = "new-texture.png"
gltf.images.append(image)
gltf.convert_images(ImageFormat.DATAURI)
gltf.images[0].uri
gltf.images[0].name
# How to find and replace the existing texture?
# ...
filename2 = "updated-3D-model.glb"
gltf.save(filename2)

you could do it with string replace in the gltf file. tried it like that and with python and string replace it works very smooth and fast.

Related

How to crop and save image obtained by inference_detector() using CascadeTabNet (openCV)?

My goal is to detect tables in images and transform such tables into CSV files.
I am using CascadeTabNet to detect the location of tables.
Their example works great (https://colab.research.google.com/drive/1lzjbBQsF4X2C2WZhxBJz0wFEQor7F-fv?usp=sharing), the problem is that it does not show at the end how to save the detected table as another image (nor how to actually make that table into a CSV file, but for that, I can use other code).
This is what they had:
from mmdet.apis import init_detector, inference_detector, show_result_pyplot
import mmcv
# Load model
config_file = '/content/CascadeTabNet/Config/cascade_mask_rcnn_hrnetv2p_w32_20e.py'
checkpoint_file = '/content/epoch_36.pth'
model = init_detector(config_file, checkpoint_file, device='cuda:0')
# Test a single image
img = "/content/CascadeTabNet/Demo/demo.png"
# Run Inference
result = inference_detector(model, img)
# Visualization results
show_result_pyplot(img, result,('Bordered', 'cell', 'Borderless'), score_thr=0.85)
I tried to add the following to their code:
model.show_result(img, result, out_file='result.jpg')
And I get the following error:
TypeError: show_result() got an unexpected keyword argument 'out_file'
I also tried adding the "out_file" inside the "show_result_pyplot":
show_result_pyplot(img, result,('Bordered', 'cell', 'Borderless'), score_thr=0.85, out_file='result.jpg')
And I get the same error: show_result() got an unexpected keyword argument 'out_file'
Finally, I tried saving the image using pyplot from matplotlib, but it did not save the cropped area (the table area of the page) but all of it:
plt.savefig('foo.png')
I have been looking for solutions (How to crop an image in OpenCV using Python, How to detect symbols on a image and save it?, How to save cropped image using openCV?, How to save the detected object into a new image ...), and they all include cv2, but that did not work for me either.
In short, how to crop the area of the table and save it as a new image after using "inference_detector()"?

Convert mp3 song image from png to jpg

I have a set of many songs, some of which have png images in metadata, and I need to convert these to jpg.
I know how to convert png images to jpg in general, but I am currently accessing metadata using eyed3, which returns ImageFrame objects, and I don't know how to manipulate these. I can, for instance, access the image type with
print(img.mime_type)
which returns
image/png
but I don't know how to progress from here. Very naively I tried loading the image with OpenCV, but it is either not a compatible format or I didn't do it properly. And anyway I wouldn't know how to update the old image with the new one either!
Note: While I am currently working with eyed3, it is perfectly fine if I can solve this any other way.
I was finally able to solve this, although in a not very elegant way.
The first step is to load the image. For some reason I could not make this work with eyed3, but TinyTag does the job:
from PIL import Image
from tinytag import TinyTag
tag = TinyTag.get(mp3_path, image=True)
image_data = tag.get_image()
img_bites = io.BytesIO(image_data)
photo = Image.open(im)
Then I manipulate it. For example we may resize it and save it as jpg. Because we are using Pillow (PIL) for these operations, we actually need to save the image and finally load it back to get the binary data (this detail is probably what should be improved in the process).
photo = photo.resize((500, 500)) # suppose we want 500 x 500 pixels
rgb_photo = photo.convert("RGB")
rgb_photo.save(temp_file_path, format="JPEG")
The last step is thus to load the image and set it as metadata. You have more details about this step in this answer.:
audio_file = eyed3.load(mp3_path) # this has been loaded before
audio_file.tag.images.set(
3, open(temp_file_path, "rb").read(), "image/jpeg"
)
audio_file.tag.save()

How to replace pixel data in same DICOM file using pyDicom to read it again with any DICOM viewer?

I want to read some DICOM files, so I'm testing pydicom for my work, which I think is considerably useful.
Now I want to load existing DICOM files, replace the pixel data array with another pixel array (e.g. pre-processing or literally another DICOM pixel array) and most of all, I want to read it again with any DICOM viewer application.
For this test, I used the tutorial code below. This code loads a test data file. The size of image is 64*64. The code below does sub-sampling from the original data. After that, the size of image is 8*8, and the result is saved to after.dcm.
But when I read the file using a DICOM viewer app (I used 'Dicompass'), the size of DICOM image is still 64*64. What is it that I'm missing?
I referred to the pydicom documentation (http://pydicom.readthedocs.io/en/stable/getting_started.html, https://pydicom.github.io/pydicom/stable/index.html) to solve my problem.
# authors : Guillaume Lemaitre <g.lemaitre58#gmail.com>
# license : MIT
import pydicom
from pydicom.data import get_testdata_files
print(__doc__)
# FIXME: add a full-sized MR image in the testing data
filename = get_testdata_files('MR_small.dcm')[0]
ds = pydicom.dcmread(filename)
# get the pixel information into a numpy array
data = ds.pixel_array
print(data)
print('The image has {} x {} voxels'.format(data.shape[0],
data.shape[1]))
data_downsampling = data[::8, ::8]
print('The downsampled image has {} x {} voxels'.format(
data_downsampling.shape[0], data_downsampling.shape[1]))
# copy the data back to the original data set
ds.PixelData = data_downsampling.tostring()
# update the information regarding the shape of the data array
ds.Rows, ds.Columns = data_downsampling.shape
# print the image information given in the dataset
print('The information of the data set after downsampling: \n')
print(ds)
print(ds.pixel_array)
print(len(ds.PixelData))
ds.save_as("after.dcm")
The code looks OK. But, you are not overwriting original file.
You load the file with:
filename = get_testdata_files('MR_small.dcm')[0]
ds = pydicom.dcmread(filename)
where original file name is "MR_small.dcm".
Then you save the file with:
ds.save_as("after.dcm")
where destination file name is different. That means, original file is still unchanged.
You should either load "after.dcm" in your DICOM viewer to test
OR
You should overwrite the file (pydicom.filewriter.dcmwrite) while saving it.
Not a part of your problem, but if you are creating copy of original image with change in pixel data, it is recommended that you also modify instance specific information in dataset like some UIDs and InstanceNumber (0020,0013), SOPInstanceUID (0008,0018) etc.

How to load images from LMDB in python without Caffe?

I want to load my image and label data from a LMDB database I created. I assign a unique key to corresponding image-label pairs and add them to the LMDB (eg. image-000000001, label-000000001). While saving the images, I convert the numpy-array of the image to string using image.tostring(). Now while loading the LMDB, I see that I can get the labels very simply by passing the keys I generated, however the image-data is shown in an encoded fashion. Doing a numpy.fromstring(lmdb_cursor.get('image-000000001')) doesn't work.
I see here - the second answer, specifically, by #Ghilas BELHADJ that one has to use Caffe-datum objects to first load the data and then fetch the image using datum.data. But I don't have such a structure where the image and label are organised using the 'data' and 'label' tags. How does one read the data correctly back in the form of a numpy image from such an LMDB in python?
In Lua, this can be achieved as follows,
local imgBin -- this is the object returned from cursor:get(image-id)
local imageByteLen = string.len(imgBin)
local imageBytes = torch.ByteTensor(imageByteLen):fill(0)
imageBytes:storage():string(imgBin)
local img = Image.decompress(imageBytes, 3, 'byte')
img = Image.rgb2y(img)
img = Image.scale(img, imgW, imgH)
I don't know how to do this in Python.
import lmdb
import cv2
import numpy as np
with lmdb.open(lmdb_dir,readonly=True).begin(write=False) as txn:
for idx,(key,val) in enumerate(txn.cursor()):
img = cv2.imdecode(np.fromstring(val,dtype=np.uint8),1)

python PIL acces multiple images from a single image file

I have written a python script to Delta compress an image. The image file format is .tif which contains 8 images. When I use the normal code ...
org_Image = Image.open(image)
org_Data = org_Image.load()
... I can only access the first image. How do I go about accessing the other ones?
You use org_Image.seek(org_Image.tell() + 1) to get the next one.
In PIL seek moves you to a given frame, (with an IO_Error if it doesn't exist), and tell reports the current frame number.

Categories

Resources