Reading DICOM 1.2.840.10008.1.2.4.70 - dicom

I have a problem when reading DICOM file. This is the format 1.2.840.10008.1.2.4.70(Process 14 with a first-order prediction (Selection Value 1). I write my own software.
Here is result of my work.
I also give you a .dcm file.
What can be wrong with it? Only RadiAnt Dicom Viewer open it corectly ( i didn't find any working software with source code ).
Have someone any tutorial about it? Any working code?
I'll be very grateful!
Thanks for help.
I show you how I it do:
//I have:
numCOL= imageWidth;
numROW= imageHeight;
dwCurrentBufferLength;//-> where I in file
//and other stuff...
//First i decode first row:
//[0][0]
DecodeFirstRow(curRowBuf,dwCurrentBufferLength);
//I calculate difrences
HuffDecode ( table , &val, dwCurrentBufferLength);
//and extend
HuffExtend(extend, val);
curRowBuf[0][curComp]=extend+(1<<(Pr-Pt-1));
//[1-n][0]
//... huff stuff
curRowBuf[col][curComp]=extend+curRowBuf[col-1][curComp];
//Then i put row to the vector:
for (col = 0; col < numCol; col++)
{
v=RowBuf[col][0]<<point_transform_parameter;
m_vOutputBuf.push_back(v);
}
//Rest of columns
//[0][m]
curRowBuf[0][curComp]=extend+prevRowBuf[0][curComp];
predictor = left =curRowBuf[leftcol][curComp];
//[1-n][m]
curRowBuf[col][curComp]=extend+predictor;
//and also put it to vector ^^
Where i must sub this 1000??

Most likely you have not accounted for the Rescale Intercept, tag (0028,1052) when calculating your HU values. According to the DICOM file, the intercept is -1000.
To get the appropriate HU values of your image, use this formula:
HU = rescale_slope * pixel_value + rescale_intercept
where Rescale Intercept is thus obtained from tag (0028,1052) and Rescale Slope from tag (0028,1053).

Here is what I see using gdcmviewer:
$ gdcmviewer 3DSlice1.dcm
GDCM is open source you could study it.

Related

How to suppress annoying stream of warnings from pointcloudlibrary `SampleConsensusModelPlane::optimizeModelCoefficients`

I have this function for fitting a plane to a pointcloud using PCL's sac model fitting. I want the best result I can get, so I want to run with seg.setOptimizeCoefficients(true).
The problem is that a lot of the time, the pointcloud passed in, will not have enough points to optimise coefficients, so I get a continuous stream of:
[pcl::SampleConsensusModelPlane::optimizeModelCoefficients] Not enough inliers found to optimize model coefficients (0)! Returning the same coefficients.
I would like to have coefficient optimisation to run when it can, and when it can't to just carry on without polluting the CLI output with many red warning messages.
according to this issue this message just means that there are fewer than 3 inlier points for the SAC model fitting. I do extract the inlier points, so I could manually check if there are 3 or more. But I can't see how to do this first, and THEN find the optimized model coefficients. Is there a way?
inline void fit_plane_to_points(
const pcl::PointCloud<pcl::PointXYZI>::ConstPtr& det_points,
const pcl::ModelCoefficients::Ptr& coefficients,
const Eigen::Vector3f& vec,
const pcl::PointCloud<pcl::PointXYZI>::Ptr& inlier_pts) {
// if no det points to work with, don't try and segment
if (det_points->size() < 3) {
return;
}
// fit surface point samples to a plane
pcl::PointIndices::Ptr inlier_indices(new pcl::PointIndices);
pcl::SACSegmentation<pcl::PointXYZI> seg;
seg.setModelType(pcl::SACMODEL_PERPENDICULAR_PLANE);
// max allowed difference between the plane normal and the given axis
seg.setEpsAngle(sac_angle_threshold_);
seg.setAxis(vec);
seg.setMethodType(pcl::SAC_RANSAC);
seg.setDistanceThreshold(sac_distance_threshold_);
seg.setMaxIterations(1000);
seg.setInputCloud(det_points);
seg.setOptimizeCoefficients(sac_optimise_coefficients_);
seg.segment(*inlier_indices, *coefficients);
if (inlier_indices->indices.empty()) {
// if no inlier points don't try and extract
return;
}
// extract the planar points
pcl::ExtractIndices<pcl::PointXYZI> extract;
extract.setInputCloud(det_points);
extract.setIndices(inlier_indices);
extract.setNegative(false);
extract.filter(*inlier_pts);
return;
}
I would say the best way to do this is to disable setOptimizeCoefficients and then do that manually after seg.segment. You basically have to recreate these lines: https://github.com/PointCloudLibrary/pcl/blob/10235c9c1ad47989bdcfebe47f4a369871357e2a/segmentation/include/pcl/segmentation/impl/sac_segmentation.hpp#L115-L123 .
You can access the model via getModel() (https://pointclouds.org/documentation/classpcl_1_1_s_a_c_segmentation.html#ac7b9564ceba35754837b4848cf448d78).
Ultimately got it working, with advice from IBitMyBytes by setting seg.setOptimizeCoefficients(false); and then manually optimising after doing my own check:
// if we can, optimise model coefficients
if (sac_optimise_coefficients_ && inlier_indices->indices.size() > 4) {
pcl::SampleConsensusModel<pcl::PointXYZI>::Ptr model = seg.getModel();
Eigen::VectorXf coeff_refined;
Eigen::Vector4f coeff_raw(coefficients->values.data());
model->optimizeModelCoefficients(inlier_indices->indices,
coeff_raw, coeff_refined);
coefficients->values.resize(coeff_refined.size());
memcpy(&coefficients->values[0], &coeff_refined[0],
coeff_refined.size() * sizeof (float));
// Refine inliers
model->selectWithinDistance(coeff_refined, sac_distance_threshold_,
inlier_indices->indices);
}

Get word at position in Atom

From a linter provider, I receive a Point compatible array(line, column) where the error occured. Now I would like to hightlight the word surrounding that point, basically the result one would get if that exact point was double-clicked in the editor. Something like
const range = textEditor.getWordAtPosition(point)
Is what I hoped for, but couldn't find in the documentation.
Thanks for your help!
After looking around for a while, there seems to be no API method for the given need. I ended up writing a small helper function based upon this answer:
function getWordAtPosition(line, pos) {
// Perform type conversions.
line = String(line);
pos = Number(pos) >>> 0;
// Search for the word's beginning and end.
const left = Math.max.apply(null, [/\((?=[^(]*$)/,/\)(?=[^)]*$)/, /\,(?=[^,]*$)/, /\[(?=[^[]*$)/, /\](?=[^]]*$)/, /\;(?=[^;]*$)/, /\.(?=[^.]*$)/, /\s(?=[^\s]*$)/].map(x => line.slice(0, pos).search(x))) + 1
let right = line.slice(pos).search(/\s|\(|\)|\,|\.|\[|\]|\;/)
// The last word in the string is a special case.
if (right < 0) {
right = line.length - 1
}
// Return the word, using the located bounds to extract it from the string.
return str.slice(left, right + pos)
}
Here, the beginning of the word is determined by the latest occurance of one of the characters (),.[]; or a blank.
The end of the word is determined by the same characters, however here the first occurance is taken as a delimeter.
Given the original context, the function can the be called using the API method ::lineTextForBufferRow and the desired postion (column) as follows:
const range = getWordAtPosition(textEditor.lineTextForBufferRow(bufferRow), 10)

sunburst.R total frequency count is incorrect

I am plotting a sunburst donut and I cannot figure out why the total is incorrect.
library(sunburstR)
reports <- data.frame(
sequence = c("SVP-VP-Dir-end","SVP-VP-Dir-end","SVP-VP-Dir-end","SVP-VP-Dir-end","SVP-No VP-Dir-end","SVP-No VP-Dir-end","SVP-No VP-Dir-end"),
freq = as.numeric(c("167","60","51","32","5","1","1")))
sunburst(reports, count = TRUE)
It is supposed to be 100% 317 of 317 . Anyone know how to fix this? There is not much documentation on this great package.
Also, I would like it to have a default value in the center of donut.
If there is another way to create an interactive donut using R, please let me know.
Thanks you in advance.
It looks like the default function generating the message in the center of the donut rounds the total value to the nearest ten.
But you can customize this function using the explanation argument of sunburst. Oddly, the customized function (in javascript) must be provided as a string.
Try the following function:
custom.message = "function (d) {
root = d;
while (root.parent) {
root = root.parent
}
p = (100*d.value/root.value).toPrecision(3);
msg = p+' %<br/>'+d.value+' of '+root.value;
return msg;
}"
Now:
sunburst(reports, explanation = custom.message )
will generate the donut displaying exact total values. The count argument is no longer needed, as it is used by the default explanation function.
The value returned by custom.message is html code. As you can see, I've just inserted a line break (<br/>). You can modify the msg return value to further customize the look and feel.

Trying to create point from X,Y, coordinate

I have used a formula to create an X and Y coordinate that I would like to create a point from. They are held in the attribute table, and I don't know how to use those points for the geometry. Here's the code:
cursor01 = arcpy.da.InsertCursor(OutPutCent,["SHAPE#X", "SHAPE#Y","Xcoord","Ycoord","totpop", "NAME","STATE_NAME","POLY_ID", "OBJECTID", "STATE_FIPS", "CNTY_FIPS", "FIPS", "FIPSnum","FIPS_NUMER" ])
#if row[0] >= 5.2:
cursor01.insertRow([XPoint,YPoint,centroid_X1,centroid_Y1,TotalPop1,thecntyName1,TheStateName1,idpoly1, idobject1, stateFIPS1, countyFIPS1, fips1, fipSnum1, fipsNumer1])
Any suggestions would be much appreciated I need to resolve this asap!
Best
This should probably be in gis.stackexchange.com.
Hard to tell what you're aiming for with that code, but I'll have a guess anyway...If you have existing points you want to relocate based on updated coordinates in an attribute table, try one of the following.
The simple no-scripting solution is this:
export your attribute table to csv
use Add XY Data to import the csv as a new layer
During the import process you can set the geometry to your Xcoord, Ycoord attribute fields, so the new dataset will have updated locations. Then just prune any records you don't want - looks like you're filtering on some value? Select by Attributes and delete rows that don't meet your condition.
Alternatively, a structurally correct template to update existing geometry with new coordinates from the attibute table is:
with arcpy.da.UpdateCursor(dataset, ['SHAPE#XY', 'point_unique_id_or_name', 'conditional_field', 'X_coord', 'Y_coord']) as cursor:
update_count = 0
for row in cursor:
if row[conditional_field_index] meets condition:
updated_point = (row[X_coord_index], row[Y_coord_index])
row[SHAPE#XY_index] = updated_point
cursor.updateRow(row)
print "{} location updated".format(row[point_unique_id_or_name_index])
update_count += 1
print "{} point locations updated".format(update_count)
You only need to reference relevant fields in the UpdateCursor - if they don't get referenced inside the for loop, don't include them.
Strongly advise you practice on a copy of your original dataset.
you need to import QPoint from QtCore:
from PyQt5.QtCore import QPoint
Then create a qpoint object:
_qpoint = QPoint()
Then add your desired x and y coordinates with the setX, and setY methods:
_qpoint.setX()
_qpoint.setY()
example:
_qpoint.setX(500)
_qpoint.setY(700)
beware of the capital X and Y in the 'set' method of the point object.
For more details, refer to this link.

Get cell types when reading and parsing excel files

I am trying to read and parse and excel and some unclear things come into play as usual for me.
Here is what i have:
while (true)
{
comVariantCell1 = cells.item(row, 1).value().variantType();
comVariantCell2 = cells.item(row, 2).value().variantType();
//if an empty cell is found, processing will stop and user will get an error message in order to solve the inconsistency.
if (comVariantCell1 != COMVariantType::VT_EMPTY && comVariantCell2 != COMVariantType::VT_EMPTY)
{
//both cells have values, check their types.
importedLine = conNull();
progress1.setText(strfmt("Importing row %1", row));
if (cells.item(row, 1).value().variantType() == COMVariantType::VT_BSTR)
{
importedLine += cells.item(row, 1).value().bStr();
}
else
{
importedLine += cells.item(row, 1).value().double();
}
importedLine += cells.item(row, 2).value().double();
importedLinesCollection += [importedLine]; //conIns(importedLinesCollection, row - 1, (importedLine));
row++;
}
else
{
info (strFmt("Empty cell found at line %1 - import will not continue and no records were saved.", row));
break;
}
}
Excel format:
Item number Transfer Qty
a100 50.5
a101 10
a102 25
This worked well to check if the cell type is string: COMVariantType::VT_BSTR
but what should i use to check for a real or integer value ?
I am pretty sure in this case, the quantity will be not contain real values but anyway, it could be useful in the future to make the difference between these two types.
I have to mention that, even if i have an int value and I use cells.item(row, 1).value().int() it won't work. I can't see why.
Why do i want to make the difference? Because if it's forbidden to have real values in the quantity column ( at least in my case ), i want to check that and give the user the opportunity to put a correct value in that place and maybe further investigate why that happened to be there.
Take a look on how it is done in \Classes\SysDataExcelCOM\readRow.
It is basically using switch to test the type. This is really boring!
Also take a look on ExcelIO, a class I made some years ago. It reads Excel and returns each row as a container. This is a more high-level approach.
As a last resort you could save the Excel as a tab separated file. Then use TextIO to read the content. This will be at least 10 times faster than using Excel!

Resources