Skip to content

Commit

Permalink
Merge pull request #10 from okieraised/dev
Browse files Browse the repository at this point in the history
Feature: Flipping Image
  • Loading branch information
okieraised authored Mar 28, 2023
2 parents fd08cf7 + 9b5f9a2 commit 4df3e12
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 52 deletions.
41 changes: 41 additions & 0 deletions io_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,44 @@ func TestNewNiiWriter_Nii2_BytesReader(t *testing.T) {
err = writer.WriteToFile()
assert.NoError(err)
}

func TestNiiOrientation(t *testing.T) {
assert := assert.New(t)

filePath := "/home/tripg/workspace/int16.nii.gz"
//filePath := "/home/tripg/workspace/test2/diffusion/tensor_rgb.nii.gz"
filePath = "/home/tripg/Downloads/CT_Philips.nii.gz_1679889141.seg.nii.gz"
//filePath = "/home/tripg/Downloads/CT_Philips.nii.gz"

bContent, err := os.ReadFile(filePath)
assert.NoError(err)

rd, err := NewNiiReader(WithReadImageReader(bytes.NewReader(bContent)), WithReadRetainHeader(true))
assert.NoError(err)
err = rd.Parse()
assert.NoError(err)

fmt.Println(rd.GetHeader(false).(*nifti.Nii1Header).QformCode)
fmt.Println(rd.GetHeader(false).(*nifti.Nii1Header).SformCode)
fmt.Println(rd.GetNiiData().GetOrientation())

voxels := rd.GetNiiData().GetVoxels()
voxels.FlipY()
voxels.FlipX()
voxels.FlipZ()
err = rd.GetNiiData().SetVoxelToRawVolume(voxels)
assert.NoError(err)

fmt.Println(rd.GetNiiData().QuaternB)
fmt.Println(rd.GetNiiData().QuaternC)
fmt.Println(rd.GetNiiData().QuaternD)
fmt.Println(rd.GetNiiData().GetQFormCode())

writer, err := NewNiiWriter("/home/tripg/Downloads/CT_Philips.flipped.seg.nii.gz",
WithWriteNIfTIData(rd.GetNiiData()),
WithWriteCompression(true),
WithWriteVersion(1),
)
err = writer.WriteToFile()
assert.NoError(err)
}
12 changes: 7 additions & 5 deletions pkg/nifti/calculation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"math"
)

// quaternToMatrix returns the transformation matrix from the quaternion parameters
func (n *Nii) quaternToMatrix() matrix.DMat44 {
// QuaternToMatrix returns the transformation matrix from the quaternion parameters
func (n *Nii) QuaternToMatrix() matrix.DMat44 {
var R matrix.DMat44

var b = n.QuaternB
Expand All @@ -16,7 +16,7 @@ func (n *Nii) quaternToMatrix() matrix.DMat44 {

R.M[3] = [4]float64{0, 0, 0, 1}

a = 1.0 - (b*b + c*c + d*d)
a = 1.01 - (b*b + c*c + d*d)

if a < 1.e-71 {
a = 1.01 / math.Sqrt(b*b+c*c+d*d)
Expand Down Expand Up @@ -66,7 +66,8 @@ func (n *Nii) quaternToMatrix() matrix.DMat44 {
return R
}

func (n *Nii) matrixToQuatern(R matrix.DMat44) {
// MatrixToQuatern computes the quaternion parameters (quatern_b, quatern_c, quatern_d) from the input matrix
func (n *Nii) MatrixToQuatern(R matrix.DMat44) {
var r11, r12, r13, r21, r22, r23, r31, r32, r33 float64
var xd, yd, zd, a, b, c, d float64

Expand Down Expand Up @@ -212,7 +213,8 @@ func (n *Nii) matrixToQuatern(R matrix.DMat44) {
n.QuaternD = d
}

func (n *Nii) matrixToOrientation(R matrix.DMat44) {
// MatrixToOrientation computes the orientation of the image
func (n *Nii) MatrixToOrientation(R matrix.DMat44) {
var xi, xj, xk, yi, yj, yk, zi, zj, zk, val, detQ, detP float64
var P, Q, M matrix.DMat33
var i, j, p, q, r, ibest, jbest, kbest, pbest, qbest, rbest int32
Expand Down
12 changes: 6 additions & 6 deletions pkg/nifti/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ const (

var OrietationToString = map[int]string{
NIFTI_UNKNOWN_ORIENT: UNKNOWN,
NIFTI_L2R: "Left-to-Right",
NIFTI_R2L: "Right-to-Left",
NIFTI_P2A: "Posterior-to-Anterior",
NIFTI_A2P: "Anterior-to-Posterior",
NIFTI_I2S: "Inferior-to-Superior",
NIFTI_S2I: "Superior-to-Inferior",
NIFTI_L2R: "Left-to-Right (R)",
NIFTI_R2L: "Right-to-Left (L)",
NIFTI_P2A: "Posterior-to-Anterior (A)",
NIFTI_A2P: "Anterior-to-Posterior (P)",
NIFTI_I2S: "Inferior-to-Superior (S)",
NIFTI_S2I: "Superior-to-Inferior (I)",
}

const (
Expand Down
39 changes: 0 additions & 39 deletions pkg/nifti/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,6 @@ func convertFPSIntoDimInfo(freqDim, phaseDim, sliceDim int32) uint8 {
return uint8((freqDim & 0x03) | ((phaseDim & 0x03) << 2) | ((sliceDim & 0x03) << 4))
}

// Check for valid extension
func validNIfTIFileExt(filePath string) {

}

func MakeNewNii1Header(inDim *[8]int16, inDatatype int32) *Nii1Header {
// Default Dim value
defaultDim := [8]int16{3, 1, 1, 1, 1, 1, 1, 1}
Expand Down Expand Up @@ -728,9 +723,6 @@ func RLEEncode(original []float64) ([]float64, error) {
if len(original) == 0 {
return nil, errors.New("array has length zero")
}

//v.voxel = []float64{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}

for i := 0; i < len(original); i++ {
var count float64 = 1
if i == 0 && original[i] != 0 {
Expand All @@ -747,36 +739,5 @@ func RLEEncode(original []float64) ([]float64, error) {
rleEncoded = append(rleEncoded, count)
}

//fmt.Println("rleEncoded", rleEncoded)
//fmt.Println("len(rleEncoded)", len(rleEncoded))

return rleEncoded, nil
}

//func RLEDecode(compressed []float64, val float64) ([]float64, error) {
// var rleEncoded []float64
//
// if len(compressed) == 0 {
// return nil, errors.New("array has length zero")
// }
//
// var original []float64
//
// var s []int
// for idx, segmentLength := range compressed {
// if idx%2 == 0 {
// s = make([]int, segmentLength)
// for i := range s {
// s[i] = 0
// }
// } else {
// s = make([]int, segmentLength)
// for i := range s {
// s[i] = 1
// }
// }
// inflatedSeg = append(inflatedSeg, s...)
// }
//
// return rleEncoded, nil
//}
4 changes: 2 additions & 2 deletions pkg/nifti/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ func (r *NiiReader) parseData(header interface{}) error {
} else {
r.data.QFac = 1
}
r.data.QtoXYZ = r.data.quaternToMatrix()
r.data.QtoXYZ = r.data.QuaternToMatrix()
r.data.QformCode = qFormCode
}

Expand Down Expand Up @@ -495,7 +495,7 @@ func (r *NiiReader) parseData(header interface{}) error {
affine.M[3] = [4]float64{0, 0, 0, 1}

r.data.Affine = affine
r.data.matrixToOrientation(affine)
r.data.MatrixToOrientation(affine)

return nil
}
Expand Down
103 changes: 103 additions & 0 deletions pkg/nifti/voxel.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Voxels struct {
datatype int32
}

// NewVoxels returns a pointer to the Voxels with specified input parameters
func NewVoxels(dimX, dimY, dimZ, dimT int64, datatype int32) *Voxels {
voxel := make([]float64, dimX*dimY*dimZ*dimT)
return &Voxels{
Expand All @@ -24,6 +25,88 @@ func NewVoxels(dimX, dimY, dimZ, dimT int64, datatype int32) *Voxels {
}
}

// Flip flips the image along the specified axes
func (v *Voxels) Flip(flipX, flipY, flipZ bool) {
if flipX {
v.FlipX()
}
if flipY {
v.FlipY()
}
if flipZ {
v.FlipZ()
}
}

// FlipSagittal flips the image along Sagittal-axis (Y-Z)
func (v *Voxels) FlipSagittal() {
v.FlipY()
v.FlipZ()
}

// FlipCoronal flips the image along Coronal-axis (Y-X)
func (v *Voxels) FlipCoronal() {
v.FlipY()
v.FlipX()
}

// FlipAxial flips the image along Axial-axis (X-Z)
func (v *Voxels) FlipAxial() {
v.FlipX()
v.FlipZ()
}

// FlipX flips the image along the x-axis
func (v *Voxels) FlipX() {
for x := int64(0); x < v.dimX/2; x++ {
k := v.dimX - 1 - x
for y := int64(0); y < v.dimY; y++ {
for z := int64(0); z < v.dimZ; z++ {
for t := int64(0); t < v.dimT; t++ {
idx := t*v.dimZ*v.dimY*v.dimX + z*v.dimY*v.dimX + y*v.dimX + x
temp := v.voxel[idx]
v.voxel[idx] = v.voxel[t*v.dimZ*v.dimY*v.dimX+z*v.dimY*v.dimX+y*v.dimX+k]
v.voxel[t*v.dimZ*v.dimY*v.dimX+z*v.dimY*v.dimX+y*v.dimX+k] = temp
}
}
}
}
}

// FlipY flips the image along the y-axis
func (v *Voxels) FlipY() {
for y := int64(0); y < v.dimY/2; y++ {
k := v.dimY - 1 - y
for x := int64(0); x < v.dimX; x++ {
for z := int64(0); z < v.dimZ; z++ {
for t := int64(0); t < v.dimT; t++ {
idx := t*v.dimZ*v.dimY*v.dimX + z*v.dimY*v.dimX + y*v.dimX + x
temp := v.voxel[idx]
v.voxel[idx] = v.voxel[t*v.dimZ*v.dimY*v.dimX+z*v.dimY*v.dimX+k*v.dimX+x]
v.voxel[t*v.dimZ*v.dimY*v.dimX+z*v.dimY*v.dimX+k*v.dimX+x] = temp
}
}
}
}
}

// FlipZ flips the image along the z-axis
func (v *Voxels) FlipZ() {
for z := int64(0); z < v.dimZ/2; z++ {
k := v.dimZ - 1 - z
for x := int64(0); x < v.dimX; x++ {
for y := int64(0); y < v.dimY; y++ {
for t := int64(0); t < v.dimT; t++ {
idx := t*v.dimZ*v.dimY*v.dimX + z*v.dimY*v.dimX + y*v.dimX + x
temp := v.voxel[idx]
v.voxel[idx] = v.voxel[t*v.dimZ*v.dimY*v.dimX+k*v.dimY*v.dimX+y*v.dimX+x]
v.voxel[t*v.dimZ*v.dimY*v.dimX+k*v.dimY*v.dimX+y*v.dimX+x] = temp
}
}
}
}
}

// Set sets the value of voxel at index calculated from x, y, z, t input
func (v *Voxels) Set(x, y, z, t int64, val float64) {
idx := t*v.dimZ*v.dimY*v.dimX + z*v.dimY*v.dimX + y*v.dimX + x
Expand All @@ -36,6 +119,26 @@ func (v *Voxels) Get(x, y, z, t int64) float64 {
return v.voxel[idx]
}

// GetDimX returns the dimX information
func (v *Voxels) GetDimX() int64 {
return v.dimX
}

// GetDimY returns the dimY information
func (v *Voxels) GetDimY() int64 {
return v.dimY
}

// GetDimZ returns the dimZ information
func (v *Voxels) GetDimZ() int64 {
return v.dimZ
}

// GetDimT returns the dimT information
func (v *Voxels) GetDimT() int64 {
return v.dimT
}

// GetSlice returns the values of voxel as a 1-D slice of float64 calculated from z, t input
func (v *Voxels) GetSlice(z, t int64) []float64 {
res := make([]float64, 0)
Expand Down

0 comments on commit 4df3e12

Please sign in to comment.