after merge fixes

This commit is contained in:
Alexander-D-Karpov 2022-11-03 22:16:11 +03:00
parent adccb5cf94
commit 1e19f7edd0
7 changed files with 77 additions and 46 deletions

View File

@ -5,6 +5,7 @@ from dicom.api.views import (
CreateRoiApi, CreateRoiApi,
CreateRulerApi, CreateRulerApi,
DeleteDicomProjectApi, DeleteDicomProjectApi,
GeneratePatology,
ListCreateDicomApi, ListCreateDicomApi,
ListCreateProjectApi, ListCreateProjectApi,
ListUpdateDicomImageNumberApi, ListUpdateDicomImageNumberApi,
@ -15,8 +16,6 @@ from dicom.api.views import (
RetrieveUpdateDeleteRoiApi, RetrieveUpdateDeleteRoiApi,
RetrieveUpdateDeleteRulerApi, RetrieveUpdateDeleteRulerApi,
SmartFileUploadApi, SmartFileUploadApi,
GeneratePatology,
GeneratePointCloud
) )
from django.urls import include, path from django.urls import include, path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
@ -123,12 +122,11 @@ urlpatterns = [
), ),
), ),
path( path(
'generate/', "generate/",
include( include(
[ [
path('patology', GeneratePatology.as_view(), name='generate_patology'), path("patology", GeneratePatology.as_view(), name="generate_patology"),
path('point_cloud', GeneratePointCloud.as_view(), name='generate_patology')
] ]
), ),
) ),
] ]

View File

@ -13,7 +13,13 @@ SECRET_KEY = env(
default="XgO9NMQfMY5CNeVNh98WrKRXiQZnvtPzHJrF9ROPhAFLVEG1FvDD2ZRKTdJKVu8p", default="XgO9NMQfMY5CNeVNh98WrKRXiQZnvtPzHJrF9ROPhAFLVEG1FvDD2ZRKTdJKVu8p",
) )
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "dev.akarpov.ru"] ALLOWED_HOSTS = [
"localhost",
"0.0.0.0",
"127.0.0.1",
"dev.akarpov.ru",
"dev2.akarpov.ru",
]
# CACHES # CACHES
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -181,3 +181,9 @@ class ProjectSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Project model = Project
fields = ["files", "slug", "created"] fields = ["files", "slug", "created"]
class PatologyGenerateSerializer(serializers.Serializer):
project_slug = serializers.CharField()
points = serializers.ListField(child=CoordinateSerializer())
depth = serializers.ListField(child=serializers.IntegerField())

View File

@ -6,7 +6,7 @@ from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.response import Response from rest_framework.response import Response
from ..models import Circle, Dicom, Project, Roi from ..models import Circle, Dicom, Project, Roi
from ..services import generate_3d_point_cloud, get_bbox, process_files from ..services import process_files
from .serializers import ( from .serializers import (
BaseShapeLayerSerializer, BaseShapeLayerSerializer,
BaseShapeSerializer, BaseShapeSerializer,
@ -15,13 +15,12 @@ from .serializers import (
FreeHandSerializer, FreeHandSerializer,
ListDicomSerializer, ListDicomSerializer,
ListProjectSerializer, ListProjectSerializer,
PointCloudSerializer, PatologyGenerateSerializer,
ProjectSerializer, ProjectSerializer,
RoiSerializer, RoiSerializer,
RulerSerializer, RulerSerializer,
SmartFileUploadSerializer, SmartFileUploadSerializer,
create_coordinate, create_coordinate,
PatologyGenerateSerializer
) )
@ -224,17 +223,6 @@ class GeneratePatology(generics.CreateAPIView):
serializer_class = PatologyGenerateSerializer serializer_class = PatologyGenerateSerializer
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
data = self.get_serializer(request.data).data # data = self.get_serializer(request.data).data
bbox = get_bbox(data['project_slug'], data['points'], data['depth']) # bbox = get_bbox(data["project_slug"], data["points"], data["depth"])
return Response(data={}, status=200) return Response(data={}, status=200)
class GeneratePointCloud(generics.CreateAPIView):
serializer_class = PointCloudSerializer
def create(self, request, *args, **kwargs):
print(request.data)
data = request.data
point_cloud = generate_3d_point_cloud(data['project_slug'])
print(point_cloud[0:5])
return Response(data={'voxels': point_cloud}, status=200)

View File

@ -1,4 +1,3 @@
from functools import lru_cache
import glob import glob
import os import os
import shutil import shutil
@ -6,18 +5,18 @@ import zipfile
from pathlib import Path from pathlib import Path
import magic import magic
import numpy as np
import pydicom
from dicom.models import Coordinate, Dicom, Project from dicom.models import Coordinate, Dicom, Project
from django.core.files import File from django.core.files import File
from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile
from skimage import measure
from stl import mesh
from utils.generators import generate_charset from utils.generators import generate_charset
from typing import List, Union
from django.conf import settings
import pydicom
def process_files( def process_files(
files: List[Union[TemporaryUploadedFile, InMemoryUploadedFile]], user, slug=None files: list[TemporaryUploadedFile | InMemoryUploadedFile], user, slug=None
): ):
if slug: if slug:
project = Project.objects.get(slug=slug) project = Project.objects.get(slug=slug)
@ -60,35 +59,56 @@ def create_coordinate(coordinates, obj):
def get_bbox(project_id, points, image_range): def get_bbox(project_id, points, image_range):
project: Project = Project.objects.get(slug=project_id) project: Project = Project.objects.get(slug=project_id)
#print(Dicom.objects.all()) # print(Dicom.objects.all())
files = project.files.all() files = project.files.all()
bbox_data = [] bbox_data = []
for file_number in range(image_range[0], image_range[1]+1): for file_number in range(image_range[0], image_range[1] + 1):
print(points[0]['x']) print(points[0]["x"])
bbox_data.append( bbox_data.append(
pydicom.dcmread( pydicom.dcmread(files[file_number].file.path)
files[file_number].file.path).pixel_array[int(points[0]['x']):int(points[1]['x']), int(points[0]['y']):int(points[1]['y'])].tolist()) .pixel_array[
int(points[0]["x"]) : int(points[1]["x"]), # noqa
int(points[0]["y"]) : int(points[1]["y"]), # noqa
]
.tolist()
)
print(pydicom.dcmread(files[file_number].file.path).pixel_array) print(pydicom.dcmread(files[file_number].file.path).pixel_array)
print(bbox_data) print(bbox_data)
#print(project.files.all(), "files", project) # print(project.files.all(), "files", project)
return [] return []
@lru_cache(512)
def generate_3d_point_cloud(project_slug: str): def generate_3d_point_cloud(project_slug: str):
project = Project.objects.get(slug=project_slug) project = Project.objects.get(slug=project_slug)
point_clouds = [] point_clouds = []
for fileindex, file in enumerate(project.files.all()[::3]): for file_index, file in enumerate(project.files.all()[::10]):
print(fileindex) print(file_index)
pixel_array = pydicom.dcmread( pixel_array = pydicom.dcmread(file.file.path).pixel_array
file.file.path for iindex, i in enumerate(pixel_array[::10]):
).pixel_array for jindex, j in enumerate(i[::10]):
for iindex, i in enumerate(pixel_array[::3]):
for jindex, j in enumerate(i[::3]):
if j <= 240: if j <= 240:
pass pass
#point_clouds.append({'x': jindex, 'y': iindex, 'z': fileindex, 'value': 0}) # point_clouds.append({'x': jindex, 'y': iindex, 'z': fileindex, 'value': 0})
else: else:
point_clouds.append([jindex, iindex, fileindex, j]) point_clouds.append([jindex, iindex, file_index, j])
return point_clouds return point_clouds
def generate_3d_model(project: Project, thr=800) -> str:
image = []
for file in project.files.all():
image.append(pydicom.dcmread(file.file.path).pixel_array)
p = np.array(image).transpose(2, 1, 0)
verts, faces, normals, values = measure.marching_cubes(p, thr, step_size=1)
solid = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype))
for i, f in enumerate(faces):
for j in range(3):
solid.vectors[i][j] = verts[f[j], :]
pth = f"/tmp/{generate_charset(4)}.stl"
solid.save(pth)
return pth

View File

@ -0,0 +1,9 @@
from celery import shared_task
from dicom.models import Project
from dicom.services import generate_3d_model
@shared_task()
def process_dicom(pk: int):
generate_3d_model(Project.objects.get(pk=pk))
return pk

View File

@ -25,5 +25,9 @@ django-cors-headers==3.13.0 # https://github.com/adamchainz/django-cors-headers
djangorestframework-simplejwt==5.2.2 djangorestframework-simplejwt==5.2.2
# DRF-spectacular for api documentation # DRF-spectacular for api documentation
drf-spectacular==0.24.2 # https://github.com/tfranzel/drf-spectacular drf-spectacular==0.24.2 # https://github.com/tfranzel/drf-spectacular
numpy==1.23.4
pydicom==2.3.0 pydicom==2.3.0
numpy==1.23.4
numpy-stl==2.17.1
scikit-image==0.19.3