阅读视图

发现新文章,点击刷新页面。
🔲 ☆

Review:A Generalized Sampling Method for Finite-Rate-of-Innovation-Signal Reconstruction

Article Address:

https://ieeexplore.ieee.org/document/4682542

Background

采样和重构无法在香农采样理论的经典框架内处理的信号,此类信号的示例包括狄拉克脉冲流和各种类型的非均匀样条,例如分段多项式、分段指数和分段谐波函数。这些信号由一组离散的参数(例如,奇点的幅度和位置)唯一指定,因此具有具有有限新率(FRI)

From Dirac Impulse to Kronecker Impulse

From Dirac impulses to Kronecker impulses

需要理解的地方就在于(4)的\(p_a(nT)\),它是由一个叫做discrete-time finite-impulse-response filter specified by the Z-transform:\(G_a(z)=\frac{1}{a}(1-e^{-aT}z^{-T})\)的filter处理后得到的。当 (3) 中的序列由 G(z) 处理时,它会产生克罗内克脉冲流,也就是(4)

Kronecker Impulse的幅度是Dirac Impulse的幅度和位置的可分函数

Two Channel sampling of a dirac impulse train

Kronecker Impulse的幅度是Dirac Impulse的幅度和位置的可分函数,这一特性可以给我们一种简单而有效的重建技术。

具体细节上,我们通过不同的采样内核获得另一组测量值,如下图: Two-channel sampling of a stream of Dirac impulses by using first-order RC networks.

然后可以通过\(p_a(nT)\)和\(p_\gamma(nT)\)建立等式计算原信号,具体见论文

Spline Equivalence and Effects

对于E样条(E-spline )采样(不确定Spline Equivalence的准确定义)与Dirac相似,通过多通道采样和不同的采样核重建信号,效果如下:

Ground truth and Reconstruction

Conclusion

总而言之,本篇论文提出了一种双通道采样方法来使用简单的计算来检索脉冲的参数来解决了采样和重建狄拉克脉冲流的典型问题。原则上,该技术适用于无限长的脉冲序列,而无需逐块处理。

这种方法和之前传统方法的比较如下图: COMPARISON OF THE STANDARD AND THE PROPOSED APPROACHES

🔲 ☆

First dive into a NFT public sale and mint

我对NFT的看法又发生了改变

我之前在买我人生第一个NFT,也就是Pixel Giraffe #6759,我认为NFT就是新时代的QQ秀变装,只不过变成了非同质化的设计(抛开技术层面来讲)。但通过对web3.0的最简单的认识,让我意识到NFT的应用当然绝对不是QQ秀变装那么简单,至少目前ta具有组建社区,身份认证,统一相同审美的人这类的作用,其中去中性化身份认证所带来后续的各种的有意思的事情我想还有更多可能。

但同时,eth链上NFT热度下降和资金转移似乎是目前不可否认的事实,这在我看来很有可能就是NFT所带来的金融属性让NFT发生了扭曲,可能具有一定价值的jepg和code通过一系列的手段“赋能”最终被项目方收割后归于虚无,我买的Pixel Giraffe #6759就是这样的一个项目,一个纯纯的韭菜。但是人家似乎也没有搞什么宣传赋能社区,单纯地贩卖重复排列组合的波普艺术,从某种意义上讲,ta也算是NFT初期探索的纯粹?😅

Boki

我在May 20号看到opensea上的trending里有了boki这个项目,boki第一眼的感觉就让我觉得说这个风格的jepg具有blue chip的潜力,如果它的目的真的是为了探索web3.0,我愿意让它成为我第一个deep dive的NFT community(同时它需要的资金我可以负担🙄)。

于是在一段时间的信息搜集和等待中,在May 20 permint后,May 22号早早爬起床,7点半就守在mint web上一直F5(因为boki final sale采用FCFS raffle,first come first server),然后8:00,准时打开小狐狸钱包,sign contract,焦急地在链上等待miner,圆圈转了1min15s后,我mint到了boki

Boki

Future

当然,NFT的价值可能会迎来暴跌,就像20世纪初的Dot-com bubble,但是或许未来又真的可以bet on crypto呢?who knows?

Can’t wait to see the Boki art reveal.

🔲 ☆

礼貌对待他人的询问,以组织架构中的通知人员为例

今天去问学校辅导员有关毕业就与去向填写的问题,让我产生了一些思考。当你充当一个被咨询的对象,或者你来发放通知后有人来询问你,又或者你是某个doc的管理人员,这个时候应该以什么样的态度来对待询问的人。

礼貌地对待doc里有的内容

当你发出通知,写好doc,很难说不会有不认真看doc的人来问你doc里有的内容,这个时候拿出讽刺和冷漠的态度在我看来是一个错误。

首先,你所理解的的事情和询问人的事情是否真的一致呢,这一点仅仅在你的一方得到确认是不够的,或许咨询的人被你呛回去后找了好久也还是找不到答案,事情得不到解决,这不就是大家最讨厌的流程卡环节的情况吗?既然大家都讨厌这样,就不要去做这样本来自己也会讨厌的事情。

其次,责任。你是不是有回答询问人的责任呢,作为一个组织架构中帮助他人的角色,比如地方基层公务员,大学辅导员,你是不是有责任来解决问题呢?如果有解决问题的需求,一个简单的回答,一个礼貌的“对不起,我不太清楚,或许这个文件里有?”或许相对于 “你有看通知吗?” 对他人来说更加温暖。更何况如果你是知道答案的,打出这个答案我想不会很花本应该是你责任与工作的时间。

额外,如果你是自愿管理一个开源项目,我想一个有礼貌的回复也会给你的project带来更好的观感。

作为与群众接触的人员,不要把自己放到敌人的位置

我时常会觉得说,有些时候有的基层工作人员好像真的是把自己放到了他所服务的群体的对立面。发通知的话,就把通知一发,别人来问就责难别人有没有看通知的呀,好像把通知一发,这套工作似乎就算完成了,其他来问的人又怎么样呢。把通知丢给他们就好了。

我不由得想起以前当通知人员的时候,我也时常犯这样的错误。

更不要去做与咨询你的人辩论的事情,不要因为利用信息差去对问你的人咄咄逼人, 更何况你还是在一个服务岗位上的时候。信息的丢失是会人感到惶恐的,本应该是救生员的你,不要去当鲨鱼。

Conclusion

这样的人,相信跟我有着同样经历的人或多或少都经历着,因为我生活在中国,所以我知道这样的基层工作人员遍布中国的大街小巷。我不知道造成的原因是什么,但是希望当大家手里有着权力的时候,哪怕是再小的权利,都可以温柔一点

🔲 ☆

Data type is medical image normalization trap

Background

I want to do preprocessing to some MRI data with .nii file extension. One of the step is normalization. As usual, when our dataset is a bunch of normal images with .png file extension, its usually a 3 Channel 8-bit image with data type is uint8. So its very common to do normalization from [0-225] to [0-1] by just dividing 255 to very pixel value.

But my dataset is all float64 aka. double type.

Wrong operation

When I first do data preprocessing, I make two fatally error.

  • Convert .nii file every slice into uint8, typical normal image in computer.
  • Do normalization to every slice

First fatal is because that I do a real lossy conversation from float64 to uint8.

imageio.imwrite(os.path.join(savePathAX, '{}.png'.format(i)), slice)

This step will auto convert your data to uint8, its a real lossy conversation.

Also, you may have a question, float64 range from 2.2E-308 to 1.7E+308, how do this code deal with the largest value.

Actually, it will make your largest value as 255. So it means that, it already do the normalization to every image from [0 - max] to [0 - 255].

Its the second fatally error.

For medical image, take CT as example:

CT Subtance HU value

You can find the pixel value mean, so you can find the data max bound and min bound[1]. And you can do the normalization easily:

MIN_BOUND = -1000.0
MAX_BOUND = 400.0

def norm_img(image): 
    image = (image - MIN_BOUND) / (MAX_BOUND - MIN_BOUND)
    image[image > 1] = 1.
    image[image < 0] = 0.
    return image

(This code also from [1])

So, image that you normalize every image into [0-1], if your every image have the bone, that’s fine. Every max value 1 represent bone. But if one of your image don’t have bone, the max HU value represent soft tissue and you normalize it into [0-1]. So different image’s 1 will have different mean, normally it means bone and some image will wrongly represent it as soft issue.

That’s why you have normalize depending on the meaning of its pixel value rather than just every image or data type max value.

Take my MRI image dataset as example, its max value is 2.6E+4 and its type is float64. If you divide it by float_max aka. 1.7E+308, all its value will be super small and if you transfer it into float32 to input into model, all its pixel value will be 0.

Lastly, in conclusion,

  • Find the pixel value mean before do normalization
  • Data type is not the guideline and most of time using float64 is for its precision rather than its range.

Appdenix

[1] https://zhuanlan.zhihu.com/p/112176670

For MRI Image, i don’t know there has the standard or not.

Replenish Apr 8, 2022

In MRI, you can do normalization to every brain because in MRI, different machine, different machine parameter will give you real different intensity. So the absolute value of MRI image intensity is not every important, the most important value is contrast information, aka. the intensity histogram. So you can do normalization to every brain separately.

“The same histogram can maintain the internal tissue contrast of your original individual and reduce the gray value difference between individuals”        —Shen (A researcher from Zhejiang University)

🔲 ☆

G-mean is not suitable for medical image instance segmentation to find threshold when background is too much

Threshold

In my undergraduate FYP, I need to do image segmentation to the brain MRI to annotate the GBM cancer in patient brain.

GBM MRI Image

I apply the famous architecture U-net to do this segmentation task. The last layer I apply is sigmoid. It outputs every pixel value in [0-1]. I was wondering which value is the best threshold for the segmentation. Threshold In the beginning, I set threshold as 0.5, but the data is very imbalance that the background is much more than the cancer area. It means that 0 value pixel is much more that 1 value pixel. It will lead to 0.5 is not a suitable value to distinguish 1 and 0. You can check this link to learn the detail:

https://towardsdatascience.com/optimal-threshold-for-imbalanced-classification-5884e870c293

ROC curve

ROC (Receiver operating characteristic), is a graphical plot that illustrates the diagnostic ability of a binary classifier system as its discrimination threshold is varied. It is created by plotting the true positive rate (TPR) against the false positive rate (FPR) at various threshold settings.

ROC Curve

It has two usages here:

  1. Compare different method in binary classification.
  2. Find best threshold for binary classification

For the usage 1, it is always using AUC (Area under curve) to determine which classification method is better.

And for usage 2, which is the part I want to talk about, it always want to choose the most up left point to be our threshold. It is very easy to understand because the more left, the false positive rate will be more less, the more up, the true positive rate will be more bigger. But how to evaluate the best left up point in ROC curve? As the article in link above shiows that, it usually use a paramter called G-mean:

G-mean

You can see that G-mean take both sensitivity and specificity into consideration. The result will be a tradeoff for 0 and 1 classification. The point here is that G-mean take 0 and 1 as the same importance. It will be great if we classify banana and apple, or some other two thing in a same significance. It will solve the imbalance.

But the question is that, in medical segmentation to segment cancer area. We do not think cancer area and normal area as same importance. So using G-mean to determine threshold will result:

I do the ROC calculating to find the bigger G-mean point to determine threshold in epoch 10, and you can see the problem.

Roc curve

Specificity

Sensitivity As you can see, to make G-mean bigger, we choose the threshold that will sacrifice specificity to increase sensitivity. Because in my dataset, the background is so much, so specificity will be so close to 1. Even you predict more cancer area, aka. more white part, the specificity will be influenced very little.

As you can see, the specificity decrease from 1 to 0.94, but the sensitivity increase from 0.65 - 1.

To be more clear, see the graph:

example The left is original image, the middle is ground truth, the right is prediction.

As you can see, the net wants to predict more white part to increase sensitivity and because it have a lot of picture with huge black part, the specificity will not be influenced more. So finally, choose the biggest G-mean point will lead to:

f1score

IoU

The most important parameter we take attention to: f1-score and IoU will dramatically decrease.

In conclusion, when you meet this situation:

  • Imbalance Data
  • You take more attention and account to the small part type of your dataset. (The Brain cancer segmentation in MRI is this typical example )

You have better not use G-mean to determine which threshold you shold deploy.

🔲 ☆

I buy my first NFT avatar

Story

Because Boring.

Because in China, cryptocurrency is totally illegal. Even I am in Singapore right now, buy ETH from some Centralized Exchanges is totally impossible. Another way to buy ETH is Decentralized exchanges (DEXs). It needs a lot of money to do this p2p exchange and I can not afford it. Luckily, I find a way to exchange BTC to ETH considering I have some BTC in hand (from Zhu Yicheng), using changelly.

Very interesting story, I find a NFT avatar have Hawaiian shirt and knitted hat which are two thing can represent me in the period of Singapore. So I think is it a real serendipity to meet it. So i decided to buy it. It is like:

NFT: Giraffe #6759 from collection Pixel Giraffes

Giraffe #6759

At last

Finally, in my opinion, I think NFT is a great way to create art and sell art. But the most NFT avatar is just a new stupid ‘换装小游戏’ or new ‘QQ秀’ that you can choose some elements provided by others to change your web avatar. It is not web3, just a new way to take your money out like 10 years ago.

☑️ ⭐

In python cv2, you need use .copy() method in Numpy to create a copy

Recently, I need to upload my graduation photo in China. There are lots of requirements, so I need to do some processing to my picture. One of them is to do offset, moving the picture pixel value down.

Because I don’t very familiar with cv2 function, so I decide to do brute force way, using for loop

new_img = img

for i in range(20, img.shape[0]):
    for j in range(img.shape[1]):
        new_img[i, j] = img[i - 20, j]

for i in range(20):
    for j in range(img.shape[1]):
        new_img[i, j] = img[i, j]

But with this code, the result will be wrong like that:

Original Image:

Wrong Results:

If you use another method to do this:

new_img = img[:235,:]
bak = img[0:20,:]


new_img = np.append(bak, new_img, axis=0)


plt.imshow(img)
plt.show()

Expected Results:

The reason why is that when you code new_img = img in python. The numpy will not create a real variable with new address. See this code:

import numpy as np

x = np.ones((255, 255, 3))
y = x

for i in range(1, x.shape[1]):
    y[i] = x[i - 1]
print(id(y))
print(id(x))

> 2410142026512
> 2410142026512

Guess what, the result is that address of x and y is the same. I guess that when numpy has some calculation will alert numpy to create a real variable. If there is just ‘=’, the numpy will not create real variable. So you need to use .copy() function to create copy of one variable, rather than ‘=’ .

I also ask this question in stackoverflow. This answer is so great. It introduce the concept about shallow copy and deep copy.

☑️ ⭐

What is .nii file?

What is .nii file?

As a BME student, I always meet .nii file though my third and fourth year in college. But I don’t understand .nii file for a long while. So I want to explain the .nii file format very simply to everyone majored in BME.

What is NIfTI?

The first thing we need to know is the background of .nii file – NIfTI (Neuroimaing Informatics Technology Initiative). NIfTI file format was envisioned about a decade ago as a replacement to the then widespread, yet problematic, analyze 7.5 file format.[1] The main problem of previous file format is lacking adequate information about orientation in space. The primary goal of NIfTI is to provide coordinated and targeted service, training, and research to speed the development and enhance the utility of informatics tools related to neuroimaging.[2]

NIfTI-1 & NIfTI-2

The new format called NIfTI-1, which was defined in two meetings of the so called Data Format Working Group(DFWG) and the National Insitutes of Health(NIH), one in the 31 March and another in 02 September of 2003[1]. NIfTI-2 improves the data types supported by NIfTI-1, as well as precision and voxel size[3]. Both .nii and .nii.gz are the common file extension name for NIfTI file format and commonly, the are both acceptable for most of software. (.nii,gz is .nii compression file)

Detail Data Information

We can learn NIfTI file by reading it metadata[4], you can also useing

info = niftiinfo(filename)

in MATLAB to read meta data from .nii file. You can see:

ans = struct with fields:
        sizeof_hdr: 348
          dim_info: ' '
               dim: [3 256 256 21 1 1 1 1]
         intent_p1: 0
         intent_p2: 0
         intent_p3: 0
       intent_code: 0
          datatype: 2
            bitpix: 8
       slice_start: 0
            pixdim: [1 1 1 1 0 0 0 0]
        vox_offset: 352
         scl_slope: 0
         scl_inter: 0
         slice_end: 0
        slice_code: 0
        xyzt_units: 0
           cal_max: 0
           cal_min: 0
    slice_duration: 0
           toffset: 0
           descrip: ''
          aux_file: ''
        qform_code: 0
        sform_code: 0
         quatern_b: 0
         quatern_c: 0
         quatern_d: 0
         qoffset_x: 0
         qoffset_y: 0
         qoffset_z: 0
            srow_x: [0 0 0 0]
            srow_y: [0 0 0 0]
            srow_z: [0 0 0 0]
       intent_name: ''
             magic: 'n+1 '

These metadata all stored in the header, which you cann look up offical doc nifti1.h to see how this metadata store. And you can use hexyl to show hex code of header info.

hexyl -n 348 filenaem.nii

There are some important header info to show how NIfTI file works.

Appendix and Reference

[1] https://brainder.org/2012/09/23/the-nifti-file-format/

[2] https://nifti.nimh.nih.gov/

[3] https://docs.safe.com/fme/html/FME_Desktop_Documentation/FME_ReadersWriters/nifti/nifti.htm

[4] https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h

❌