Comments (6)
The rendering never have been perfectly thread-safe. many values have been stored in local fields of the class. This become more critical with EnhancedCT or EnhancedMR where the rendering of frames are using different pipelines and therefore the pipielines are recalcualted depending on the last rendered frame, and then it happes that the right pixel data was loaded, but rendered with the wrong pipeline.
This is, why the rendering has been redesigned.
@tboby Would you be so kind and do the testing with the code in the following branch:
https://github.com/fo-dicom/fo-dicom/tree/GH917-RenderingOfEnhanced
This should be stable, even if the code is not yet optimized.
from fo-dicom.
@tboby Would you be so kind and do the testing with the code in the following branch:
https://github.com/fo-dicom/fo-dicom/tree/GH917-RenderingOfEnhanced
This should be stable, even if the code is not yet optimized.
This doesn't change the failing test: I don't think it's really a problem with the rendering, more with accessing Data from StreamByteBuffer in parallel. The same test adjusted to avoid DicomPixelData completely:
[Fact]
public void DirectOtherWord()
{
// Arrange
var inputFile = new FileInfo(TestData.Resolve("GH645.dcm"));
using var fs = File.OpenRead(inputFile.FullName);
using var ms = new MemoryStream();
fs.CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin);
var streamByteDicomFile = DicomFile.Open(ms);
var referencePixelData = streamByteDicomFile.Dataset.GetDicomItem<DicomOtherWord>(DicomTag.PixelData);
var pixelData = DicomPixelData.Create(streamByteDicomFile.Dataset);
var numberOfFrames = streamByteDicomFile.Dataset.GetSingleValue<int>(DicomTag.NumberOfFrames);
var referenceBytes = Enumerable.Range(0, numberOfFrames).Select(x =>
{
var offset = (long)pixelData.UncompressedFrameSize * x;
IByteBuffer buffer = new RangeByteBuffer(referencePixelData.Buffer, offset, pixelData.UncompressedFrameSize);
return buffer.Data;
})
.ToArray();
// Act
var streamBytePixelData = (streamByteDicomFile.Dataset.Clone()).GetDicomItem<DicomOtherWord>(DicomTag.PixelData);
Parallel.For(0, 10000, i =>
{
var index = i % numberOfFrames;
var offset = (long)pixelData.UncompressedFrameSize * index;
IByteBuffer frame = new RangeByteBuffer(streamBytePixelData.Buffer, offset, pixelData.UncompressedFrameSize);
Assert.Equal(referenceBytes[index], frame.Data);
});
}
I also ran our very small sanity check regression testset against that build: YBR_RCT and YBR_ICT failed, so I guess that temporary fix changing the photometric interpretation was doing something :)
from fo-dicom.
Thanks, I see. The test only runs green (and slow) if the StreamByteBuffer gets a lock in all the Read-methods wher the stream position is set and then stream.Read is called.
But: with the new branch, where the actual pixeldata is cached within the DicomImage object instead of recreated on every RenderImage call, the likelyhood of this race condition is lowered dramatically.
so, to solve this, StreamByteBuffer and FileByteBuffer (the only two classes I found, where random access to an underlying stream by setting position and then reading from stream) require to have a lock mechanism.
from fo-dicom.
The other thing, that interests me very much, is the YBR_RCT and YBR_ICT fail. I would really appreciate, if you could post some sample image to the discussion of the PR #1591 Because actually, my render tests did not show any regression, but rendered everything without issue.
Because the rendering was buggy until now, the rendering code in my application does some corrections and manipulations. With the new branch, you should throw that all away and just call DicomImage.RenderImage method and avoid that the "old workaround-code" now breaks the correct rendering.
Thanks!!
from fo-dicom.
The test only runs green (and slow) if the StreamByteBuffer gets a lock in all the Read-methods wher the stream position is set and then stream.Read is called.
While this seems very slow, it shouldn't be that bad in reality as the decoding should dominate time compared to the stream reading.
where the actual pixeldata is cached within the DicomImage object instead of recreated on every RenderImage call, the likelyhood of this race condition is lowered dramatically.
We're only reading each frame once, and the memory usage of caching pixeldata would likely be a bigger pressure on resources than the cost of fast turbo-jpeg decoding. However, we also strip all overlay tags so our use-case is a little different. The caching seems great for an interactive viewer!
FileByteBuffer
The weird thing is that we don't experience this with FileByteBuffer: it was only when we swapped to sometimes accepting streams that it started happening. It looks like it might be creating a new FileStream per Read, which avoids the problem.
I would really appreciate, if you could post some sample image to the discussion of the PR #1591
Will do!
from fo-dicom.
You're right, in real world all the other processing like decoding, rendering etc would be dominating the actual reading.
And with the caching, thats right. if you have some viewing applicaiton, where you call the rendering of the same frames often, then this is good for performance, for applications that only open a file, render each frame once and then are done, this caching is rather bad. This is why there is a property DicomImage.CacheMode where you can activate to cache everything, or nothing or something in between.
Your right, the FileByteBuffer creates a new reading stream on each access, did not see that yesterday when I searched for all setter-accessed to stream.position. So it's just about synclock access to StreamByteBuffer.
Thanks for pointing at this!
from fo-dicom.
Related Issues (20)
- Specific character set doesn't not comply with standards HOT 1
- Issues with reading PixelData HOT 2
- CSTORE fails on .NET CORE 7.0 using 5.1.1 with 'UnexpectedPDUParameter' but works on Framework 4.7.2 using 4.0.8 HOT 3
- C-Echo SCU/SCP Not working HOT 5
- Nuget shows versions of fo-dicom.NLog that are not available HOT 2
- Documentation: Usage of AdvancedDicomClient correct? HOT 1
- Setting FallbackEncoding on AdvancedDicomClientConnectionRequest has no effect on C-Find requests HOT 1
- 'IImage' does not contain a definition for 'AsTexture2D' HOT 3
- DicomTransferSyntax.Entries does not contain the fragmentable transfer syntaxes
- The DicomImage method cannot be called correctly in version 5.0, and there is no pixelData in the returned instance HOT 2
- Cannot render a DICOM file to System.Drawing.Bitmap under .netstandard2.0 HOT 1
- Being able to compare datasets HOT 8
- System.IO.FileNotFoundException: 'Could not load file or assembly 'Microsoft.Extensions.DependencyInjection, Version=6.0.0.0 HOT 3
- Handle ExplicitVR DICOM file contains invalid VR HOT 2
- Issue updating ContourImageSequence HOT 2
- Unsupported Transfer Syntax Error for Lossy JPEG 8 Bit Image Compression in fo-dicom on .NET 7.0 HOT 2
- MaxClientsAllowed still behaves incorrectly when the connections are full and open connections take longer than one minute to shutdown
- CSTORE Association before sending the request because of multiple presentation contexts HOT 7
- Strong memory use surge on HTTP request to DicomService HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fo-dicom.