How to read DICOM private tags without reading/loading pixel data? - dicom

I would like to read DICOM private tags. These private tags are under hexadecimal tag x7fe11001.
I know one of the pydicom configurations that read till pixel data starts (so the memory is not loaded up).
pydicom.dcmread(raw, defer_size="2 MB", stop_before_pixels=True)
But the private tags I am trying to read are after the pixel data. So I am ending loading complete file in memory which is not optimal. What are the other ways to read it in an optimal way?
I know there is a config param for the above method, called specific_tags. But I could not find any examples of how to use it.
Any suggestions to read DICOM metadata without loading pixel data into memory would be awesome.

You are right, specific_tags is the correct way to do this:
ds = pydicom.dcmread(raw, specific_tags=[Tag(0x7fe1, 0x1001)]
In this case, ds shall contain only your private tag and the Specific Character Set tag (which is always read).
As DICOM is a sequential format, the other tags still have to be skipped over one by one, but their value is not read.
Note that you can put any number of tags into the specific_tags argument.

Related

Make basic Math in Draw.io (diagrams.net)

I want to make some basic math stuff like Sum in Diagrams.net (old Draw.io).Is it possible ?
Exemple : I create a new parameter on a shape, like "Elec : T16" and make several copy on this shape. Is it possible to have a Text which can give me the total of the shape with this parameter ?
Best Regards.
I search a lot in the Diagrams.net blog but anything relevent.
This is not supported.
Regards,
I also wanted to do something similar and while it doesn't seem possible to do it completely in the software (as of v20.3.0), I did find a bit of a workaround: If you add properties to the shape data, then do File > Export As > XML, the properties will be there in the XML data. You can then count them one of two ways:
Open the XML file with a text editor like Notepad++, do a find on the value you want to count. If you choose "Find All" it will tell you how many times it appears.
Use a programming language like Python to read through the file and count the instances of that value.
Example:
I created a red circle in a new diagram, edited the text to say "RedCircle" and used Edit Data to add a property called TestValue, to which I assigned a value of 1. When I exported to XML it contained this element:
<object label="RedCircle" TestValue="1" id="6byQ5fOap-RXn7mFit_J-1">
Notes
When you export, make sure you turn off the Compressed option, this will create an unusable file.
Don't use Save As > XML, this will also use compression.
Diagrams.net natively saves in a compressed XML format, with only slight differences between that and the other compressed XML options, but it seems happy to also read in the exported uncompressed XML. I didn't test but if you go the programming route and want to take it a step further, it seems you could have the program update the value of a given "counter" element with the count, then open the XML file in diagrams.net to see the updated value and save it as a native .drawio file or publish in whatever format you like.
Edit: I discovered that under File > Properties you can turn off the compression on the actual .drawio file. If you do that you can just work from this file instead of exporting, but you might want to check the size of your file with and without it.
I'm sure a plugin could be created to do all of that within the app itself, but the other methods are enough for me at this point.
Hope this helps you!

What is the meaning of ngx_http_request_s::exten

I want to know the meaning of the exten, which is one member of the structure ngx_http_request_t, also, ngx_http_set_exten hopes to be excavated.
I believe that it means file extension, being the part of the final path element that follows a period. It is used to lookup the MIME type in the types data structure, to be used in the response.
Relevant code is here. Line 1701.

creating a new DICOM file from existing DICOM file using DCMTK

I am trying to create a new DICOM file from an existing DICOM file. So, the scenario is that I have a DICOM file and I do some image processing on it and produce a transformed/processed file and I would like to save it using the original file as a template.
The only things that change are
1: The pixel data
2: The rescale and offset tags.
Does anyone know how I can achieve this with DCMTK? I looked at various examples but most of them show how to save a JPG or BMP image into a new DICOM file.
If you modify the image data (Pixel Data), you should save the new dataset with new Series Instance UID and SOP Instance UID. In addition, you should also update the first value of Image Type (0008, 0008) to “DERIVED” to reflect that image is not the original image. The second value Image Type tag can be “PRIMARY” or “SECONDARY” depending on the patient examination characteristics. You can also use Derivation Description (0008, 2111) and Derivation Code Sequence (0008,9215) to describe the way in which the image was derived. In addition, you can also reference the source image(s) used to create the Derived image by adding optional Source Image Sequence (0008,2112) which can hold a list of Referenced SOP Class UID (0008,1150)/ Referenced SOP Instance UID (0008,1150) pair(s).
Kinldy check dcmodify executable and check the help in command, it has the option to modify the tags.
For anything but pixel data dcmodify is the tool of your choice.
For the pixel data you can use dcmdump to extract the pixel data to a RAW file, change it and use dump2dcm to re-integrate it into the DICOM file

Downloading >10,000 rows from database table in asp.net

How should I go about providing download functionality on an asp.net page to download a series of rows from a database table represented as a linq2sql class that only has primitive types for members (ideally into a format that can be easily read by Excel)?
E.g.
public class Customer
{
public int CustomerID;
public string FirstName;
public string LastName;
}
What I have tried so far.
Initially I created a DataTable, added all the Customer data to this table and bound it to a DataGrid, then had a download button that called DataGrid1.RenderControl to an HtmlTextWriter that was then written to the response (with content type "application/vnd.ms-excel") and that worked fine for a small number of customers.
However, now the number of rows in this table is >10,000 and is expected to reach upwards of 100,000, so it is becoming prohibitive to display all this data on the page before the user can click the download button.
So the question is, how can I provide the ability to download all this data without having to display it all on a DataGrid first?
After the user requests the download, you could write the data to a file (.CSV, Excel, XML, etc.) on the server, then send a redirect to the file URL.
I have used the following method on Matt Berseth blog for large record sets.
Export GridView to Excel
If you have issues with the request timing out try increasing the http request time in the web.config
Besides the reasonable suggestion to save the data on server first to a file in one of the answers here, I would like to also point out that there is no reason to use a DataGrid (it’s one of you questions as well). DataGrid is overkill for almost anything. You can just iterate over the records, and save them directly using HtmlTextWriter, TextWriter (or just Response.Write or similar) to the server file or to a client output stream. It seems to me like an obvious answer, so I must be missing something.
Given the number of records, you may run into a number of problems. If you write directly to the client output stream, and buffer all data on server first, it may be a strain on the server. But maybe not; it depends on the amount of memory on the serer, the actual data size and how often people will be downloading the data. This method has the advantage of not blocking a database connection for too long. Alternatively, you can write directly to the client output stream as you iterate. This may block the database connection for too long as it depends on the download speed of the client. But again; it your application is of a small or medium size (in audience) then anything is fine.
You should definitely check out the FileHelpers library. It's a freeware, excellent utility set of classes to handle just this situation - import and export of data, from text files; either delimited (like CSV), or fixed width.
It offer a gazillion of options and ways of doing things, and it's FREE, and it works really well in various projects that I'm using it in. You can export a DataSet, an array, a list of objects - whatever it is you have.
It even has import/export for Excel files, too - so you really get a bunch of choices.
Just start using FileHelpers - it'll save you so much boring typing and stuff, you won't believe it :-)
Marc
Just a word of warning, Excel has a limitation on the number of rows of data - ~65k. CSV will be fine, but if your customers are importing the file into Excel they will encounter that limitation.
Why not allow them to page through the data, perhaps sorting it before paging, and then give them a button to just get everything as a cvs file.
This seems like something that DLinq would do well, both the paging, and writing it out, as it can just fetch one row at a time, so you don't read in all 100k rows before processing them.
So, for cvs, you just need to use a different LINQ query to get all of the rows, then start to save them, separating each cell by a separator, generally a comma or tab. That could be something picked by the user, perhaps.
OK, I think you are talking too many rows to do a DataReader and then loop thru to create the cvs file. The only workable way will be to run:
SQLCMD -S MyInstance -E -d MyDB -i MySelect.sql -o MyOutput.csv -s
For how to run this from ASP.Net code see here. Then once that is done, your ASP.Net page will continue with:
string fileName = "MyOutput.csv";
string filePath = Server.MapPath("~/"+fileName);
Response.Clear();
Response.AppendHeader("content-disposition",
"attachment; filename=" + fileName);
Response.ContentType = "application/octet-stream";
Response.WriteFile(filePath);
Response.Flush();
Response.End();
This will give the user the popup to save the file. If you think more than one of these will happen at a time you will have to adjust this.
So after a bit of research, the solution I ended up trying first was to use a slightly modified version of the code sample from http://www.asp.net/learn/videos/video-449.aspx and format each row value in my DataTable for CSV using the following code to try to avoid potentially problematic text:
private static string FormatForCsv(object value)
{
var stringValue = value == null ? string.Empty : value.ToString();
if (stringValue.Contains("\"")) { stringValue = stringValue.Replace("\"", "\"\""); }
return "\"" + stringValue + "\"";
}
For anyone who is curious about the above, I'm basically surrounding each value in quotes and also escaping any existing quotes by making them double quotes. I.e.
My Dog => "My Dog"
My "Happy" Dog => "My ""Happy"" Dog"
This appears to be doing the trick for now for small numbers of records. I will try it soon with the >10,000 records and see how it goes.
Edit: This solution has worked well in production for thousands of records.

Deleting / Replacing A Node in E4X (AS3 - Flex)

I'm building a listing/grid control in a Flex application and using it in a .NET web application. To make a really long story short I am getting XML from a webservice of serialized objects. I have a page limit of how many things can be on a page. I've taken a data grid and made it page, sort across pages, and handle some basic filtering.
In regards to paging I'm using a Dictionary keyed on the page and storing the XML for that page. This way whenever a user comes back to a page that I've saved into this dictionary I can grab the XML from local memory instead of hitting the webservice. Basically, I'm caching the data retrieved from each call to the webservice for a page of data.
There are several things that can expire my cache. Filtering and sorting are the main reason. However, a user may edit a row of data in the grid by opening an editor. The data they edit could cause the data displayed in the row to be stale. I could easily go to the webservice and get the whole page of data, but since the page size is set at runtime I could be looking at a large amount of records to retrieve.
So let me now get to the heart of the issue that I am experiencing. In order to prevent getting the whole page of data back I make a call to the webservice asking for the completely updated record (the editor handles saving its data).
Since I'm using custom objects I need to serialize them on the server to XML (this is handled already for other portions of our software). All data is handled through XML in e4x. The cache in the Dictionary is stored as an XMLList.
Now let me show you my code...
var idOfReplacee:String = this._WebService.GetSingleModelXml.lastResult.*[0].*[0].#Id;
var xmlToReplace:XMLList = this._DataPages[this._Options.PageIndex].Data.(#Id == idOfReplacee);
if(xmlToReplace.length() > 0)
{
delete (this._DataPages[this._Options.PageIndex].Data.(#Id == idOfReplacee)[0]);
this._DataPages[this._Options.PageIndex].Data += this._WebService.GetSingleModelXml.lastResult.*[0].*[0];
}
Basically, I get the id of the node I want to replace. Then I find it in the cache's Data property (XMLList). I make sure it exists since the filter on the second line returns the XMLList.
The problem I have is with the delete line. I cannot make that line delete that node from the list. The line following the delete line works. I've added the node to the list.
How do I replace or delete that node (meaning the node that I find from the filter statement out of the .Data property of the cache)???
Hopefully the underscores for all of my variables do not stay escaped when this is posted! otherwise this.&#95 == this._
Thanks for the answers guys.
#Theo:
I tried the replace several different ways. For some reason it would never error, but never update the list.
#Matt:
I figured out a solution. The issue wasn't coming from what you suggested, but from how the delete works with Lists (at least how I have it in this instance).
The Data property of the _DataPages dictionary object is list of the definition nodes (was arrived at by a previous filtering of another XML document).
<Models>
<Definition Id='1' />
<Definition Id='2' />
</Models>
I ended up doing this little deal:
//gets the index of the node to replace from the same filter
var childIndex:int = (this._DataPages[this._Options.PageIndex].Data.(#Id == idOfReplacee)[0]).childIndex();
//deletes the node from the list
delete this._DataPages[this._Options.PageIndex].Data[childIndex];
//appends the new node from the webservice to the list
this._DataPages[this._Options.PageIndex].Data += this._WebService.GetSingleModelXml.lastResult.*[0].*[0];
So basically I had to get the index of the node in the XMLList that is the Data property. From there I could use the delete keyword to remove it from the list. The += adds my new node to the list.
I'm so used to using the ActiveX or Mozilla XmlDocument stuff where you call "SelectSingleNode" and then use "replaceChild" to do this kind of stuff. Oh well, at least this is in some forum where someone else can find it. I do not know the procedure for what happens when I answer my own question. Perhaps this insight will help someone else come along and help answer the question better!
Perhaps you could use replace instead?
var oldNode : XML = this._DataPages[this._Options.PageIndex].Data.(#Id == idOfReplacee)[0];
var newNode : XML = this._WebService.GetSingleModelXml.lastResult.*[0].*[0];
oldNode.parent.replace(oldNode, newNode);
I know this is an incredibly old question, but I don't see (what I think is) the simplest solution to this problem.
Theo had the right direction here, but there's a number of errors with the way replace was being used (and the fact that pretty much everything in E4X is a function).
I believe this will do the trick:
oldNode.parent().replace(oldNode.childIndex(), newNode);
replace() can take a number of different types in the first parameter, but AFAIK, XML objects are not one of them.
I don't immediately see the problem, so I can only venture a guess. The delete line that you've got is looking for the first item at the top level of the list which has an attribute "Id" with a value equal to idOfReplacee. Ensure that you don't need to dig deeper into the XML structure to find that matching id.
Try this instead:
delete (this._DataPages[this._Options.PageIndex].Data..(#Id == idOfReplacee)[0]);
(Notice the extra '.' after Data). You could more easily debug this by setting a breakpoint on the second line of the code you posted, and ensure that the XMLList looks like you expect.

Resources