Nils-Tack / Fish-swimming-masks-pressure-and-forces

Script used to prepare PIV data files, create masks/outlines from images, manually correct outlines (if necessary),compute pressure fields, thrust and drag forces acting on the body, and the Froude efficiency. Please refer to the following publication for details about pressure field calculations from 2D velocity fields: Dabiri, J. O., Bose, S., Gemmell, B. J., Colin, S. P. and Costello, J. H. (2014). An algorithm to estimate unsteady and quasi-steady pressure fields from velocity field measurements. J. Exp. Biol. 217, 331–336.
Creative Commons Zero v1.0 Universal
2 stars 3 forks source link

您好 ,想问一下问题 #1

Open Mrzhengbowen opened 2 years ago

Mrzhengbowen commented 2 years ago

您好,我想咨询您一些关于piv处理的问题

Nils-Tack commented 2 years ago

After a quick translation, I gathered that you had questions about PIV processing. The script that I uploaded (which is not perfect by any means) was written assuming that the original velocity files used to compute pressure fields are n x 4 matrix in which the columns are: x (in my case in mm), y, x velocity (m s-1), and y velocity. I used DaVis to compute pressure fields. If using another software/program (PIV lab for example), only minor modifications of the scripts are needed to assign the corresponding data to the variables of interest.

Mrzhengbowen commented 2 years ago

I mean, I'm curious about your handling of the picture of the fish in the PIV, how did you do it

Mrzhengbowen commented 2 years ago

非常感谢您抽空回答我的问题!☺

Nils-Tack commented 2 years ago

So, when it comes to calculating velocity fields from the high-speed high-resolution (4K) videos, DaVis handles pretty much everything on its own. From experience, with the fish being entirely visible in the frame, and when recording at 1000fps, the best settings used to get high-quality velocity fields with low error are: -increment between frames = 2 (or equivalent to 0.002s at 1000fps) -interrogation window size = 9664 with 75% overlap (to avoid errors due to not having enough particles per interrogation windows; 75% overlap also brings back the velocity field to 128128 vectors per frame with no post-processing smoothing or interpolation needed)

But if you are wondering about why the first part of the script that I provided goes through the transformation of the original images to black and white (BW) masks to, then, create outlines (stored as x and y coordinates), this is because the pressure function requires a mask to be used to define the boundaries of the fish, and this mask must be x and y coordinates. The conversion from gray-scale images to BW images is a little crude since I only use basic morphological operations to extract the brightest object in the frame. These operations also include functions to remove those sections of the frame that I do not want to include or that may affect the proper separation of the fish from the background, such as the bright edges of the swim tunnel. In most cases, this method is rather effective with fishes given the simplicity of their morphology. You can adjust some parameters to play a bit with contrast and thresholds to include darker sections of the animal or in contrary to decrease the brightness of areas around the fish that may add unnecessary noise. The function where those settings can be changed is called makeMask3 (check the read me file for additional details). This is by far not the most elegant way to manipulate images to prepare then for mask extraction, but it worked very reliably for me for months so I never thought about improving it much more. But who knows, if I ever feel like the whole process could be simplified even more, I may get back to it and make improvements.

Hopefully I answered your question. Otherwise, don't hesitate to ask about some of the specifics. I'll do my best to get back to you quickly.

Cheers,

Mrzhengbowen commented 2 years ago

非常感谢您的回答,不过我还是有一些地方不太懂。例如,(Note the brighter horizontal bands allowing sections of the snout and the tails to be better separated from the background to produce more accurate masks),我不是很懂您是怎么把鱼变成这么亮的,这样可以完美的把鱼与背景分离,如果我懂您这一步是怎么做到的,我可以直接运用Canny算法就可以接下来的鱼体形态处理,您可以帮我解答一下怎么实现的把鱼体变亮操作吗

Cheers,

Nils-Tack commented 2 years ago

Hi, Ok, now I see what your issue is. Similar to your approach, I originally intended to use the Canny algorithm to detect edges in the frame, so in theory I wouldn’t have to worry about making any sections brighter or darker. But it turned out poorly and was very inefficient at creating valid masks. A simple, yet fairly efficient way to obtain the silhouette of the fish was simply to separate it from the dark background by playing with contrast and brightness on the entire original gray scale image and/or on sections of the image. In summary here is what I do: I only perform basic processing of the raw image to improve its overall quality. I do this by applying both local and image-wise changes in brightness and contrast. This allows me to generate a very clean binary mask that can be used for a number of things such as extracting the outline, but also perform morphological operations to dilate the mask (useful to stay away from the boundary layer if you calculate pressures), centerlines, or anything else that can be done using a logical BW image (see Matlab doc about BW image processing that often solves a lot of issues that would arise by trying to use edge detection algorithms: https://www.mathworks.com/help/images/ref/bwmorph.html)

Here is a more thorough breakdown of what happens in the ‘makeMask3’ function:

This may not be the most elegant nor the fastest way to extract the outline of a fish, but it generally performs well and has never slowed me down enough to convince me to develop machine learning algorithms that may actually be even more capable (something to think about in the future?).

Hope this help!

Cheers,

Mrzhengbowen commented 2 years ago

非常感谢您的回答!!!您的回答点悟了我,通过您的回答我对如何处理鱼体的操作有了重要的认知,接下来我要用这个方法去研究处理我的实验,非常感谢您的帮助,有了您的帮助,我的实验会有重大的科研成果哈哈,我要先去参考一下您的makeMask3脚本,之后有问题我也会及时向您提的,非常感谢您

cheers!

Nils-Tack commented 2 years ago

My pleasure ;-) I wish I had these tools available when I started my PhD. As far as I know, the earlier version of these scripts has already been used in one of my publications (Tack, N. B., Du Clos, K. T., & Gemmell, B. J. (2021). Anguilliform Locomotion across a Natural Range of Swimming Speeds. Fluids, 6(3), 127.), and I just submitted a paper that is currently under review in JEB where I extended these methods to the study of the centerline of the fish and several other important parameters extracted automatically (advance ratio, amplitude, frequency, angle of attack of the tail...) => Tack, N. B. and Gemmell, B. J. (in review). A tale of two fish tails: Does a forked tail really perform better than a truncate tail when cruising? J. Exp. Biol.

You can find additional resource at the following DOI, which links the repository where all these analytical methods are stored. Lastly, I am still considering making a short video tutorial regarding this entire script. Nothing crazy, but at least it would show what to do, how, and in which sequence. I'll keep you posted when it's ready.

Cheers,

Mrzhengbowen commented 2 years ago

非常厉害,你真的很优秀我的朋友,你的指导对我来说很重要,我的下一篇论文很快就可以写出来,这对我攻读博士也打下了铺垫,谢谢你! 期待你的教程视频完成的那天,我一定会仔细观看研究并点赞的哈哈 祝你能成功攻读下博士学位,好运!!!

cheers!

Mrzhengbowen commented 2 years ago

你好, 尊敬的Nils Tack博士,我又来问问题了,我在阅读您的这篇文献(Nils B. T ack 1,*, Kevin T. Du Clos 2 and Brad J. Gemmell Anguilliform Locomotion across a Natural Range of Swimming Speeds)看到了您的关于珊瑚鲶鱼的视频数据,想询问您的拍摄场景是在水缸两边往鱼的身上打强白光吗?

我在做实验的过程中没有往鱼两边打光,只是从鱼的后面打了一束绿色激光使得我看清水中的粒子,但是鱼体还是黑暗模糊不清,与您的原始数据(B00001.jpg)相差的很多(您的实验原始数据中鱼体很明亮)

经过图像处理的手段后,把原始图像变成灰度图像,在修改您的脚本稍微处理,鱼体明亮效果还不是很明显,这是不是因为我没有在鱼体两边打上强光的原因呢?

后面对于鱼体形态处理及提取鱼体轮廓的操作我能理解并且处理,但是对于像您那样的原始数据(B00001.jpg)我感觉我很难实现,很难理解他怎么实现这么亮的

希望能得到您的解答!

致尼尔斯.塔克博士

cheers,

Mrzhengbowen commented 2 years ago

您的珊瑚鲶鱼的视频是将每个处理过的图像 组会在一起合成的视频吗

Nils-Tack commented 2 years ago

Hi, These coral catfish ended up being a weird exception when performing PIV. For some reason, their body would reflect and scatter light a lot more than any other fish that I have experimented with. For any of the experiments that involved fish, I always used infrared lasers (as opposed to green). Because our cameras were very sensitive to IR light, the videos appear to be quite bright, and the body of the fish was rather uniform and somewhat easy to separate from the background. But lighting, and in particular the direction from which light comes from, is critical during PIV, and in some cases, even simple shadows can spell disaster when processing PIV (speaking from experience here). This is why, when possible, I always try to use 2 overlapping lasers on either side of the fish. This way it is impossible to cast any shadows and the particle fields is uniform.

If you only have access to one laser, I think that you did the smart thing. Placing the laser behind the fish ensures that you shine some light on both sides of the body and get a sense of the flow around the fish. However, this comes at a cost: during undulation, some of the light will be masked by the tail and will considerably lower the light intensity near the body of the fish, specifically in the trough of a body wave. This may not be critical in some cases, but I assume that one of the reasons why you are performing PIV on a swimming fish is to capture the animal-fluid interactions and near-body fluid flow.

There would be two solutions to your problem. One involves the experimental setup itself, and the other one requires a few software manipulations. Before I go into too many details, can you please tell me a bit more about your setup? What camera are you using (color/grayscale)? What is the max intensity of your green laser? How big is your animal and the test section of your experimental vessel? These questions may be basic, but they are determinant to see where the problem may be.

So let’s get back to those solutions:

%% Read image rgb = imread('peppers.png'); % load a random color image figure; imshow(RGB)

%% check RGB histograms r = rgb(:,:,1); % red channel g = rgb(:,:,2); % green channel b = rgb(:,:,3); % blue channel

figure; subplot (2,2,1) histogram(r,'BinMethod','integers','FaceColor','r','EdgeAlpha',0,'FaceAlpha',1) hold on histogram(g,'BinMethod','integers','FaceColor','g','EdgeAlpha',0,'FaceAlpha',0.7) histogram(b,'BinMethod','integers','FaceColor','b','EdgeAlpha',0,'FaceAlpha',0.7) xlabel('RGB value') ylabel('Frequency') title('Color histogram in RGB color space') xlim([0 257])

subplot (2,2,2) imshow(r) title('Red channel')

subplot (2,2,3) imshow(g) title('Green channel')

subplot (2,2,4) imshow(b) title('Blue channel')

Hopefully I did not drown you in all these details, but that should at least help you avoid making the same mistakes that I made when I started.

Cheers, Nils

mojarra

Nils-Tack commented 2 years ago

The videos of the coral catfish are the unprocessed original videos (turned to image sequence for processing) for each swim trial. Because the particle fields was not always the cleanest, I used some of the image pre-processing tools in DaVis to normalize the intensity of the particle fields and obtain homogenous fields. When it comes to extracting the outline of the fish though, I pre-processed the videos (initially with lightroom, but later using an older and less capable matlab script) to separate the edges of the fish from the background.

Mrzhengbowen commented 2 years ago

hi, 谢谢您的解答,Nils博士,通过您的回答了解到您在对任何涉及鱼的实验都用的是红外激光,但是我在看珊瑚鲶鱼的游泳视频时看到的是白色的反射光呀,这是为什么呢?(您在后面说珊瑚鲶鱼的视频时未经处理的原始实验视频)

后续我觉得我应该也会学习您的做法,从两边去打光,这样会让阴影尽可能的减少。实验设置本身,我是用黑布蒙住了鱼缸周围和底部,之前做实验可能比较马虎,相机直接选择的iphone11自带的相机,所以在性能上没有那么好(锐度、边缘、像素差),选择的鱼种是草金鱼,实验容器是25X25X25cm。

通过看您的珊瑚鲶鱼视频,我也发现了,在尾巴附近是有某种光晕的,但是看到您的脚本示例图片中那条鱼周围是没有光晕的,这是因为,您对脚本示例图片进行了处理吗?还是因为这种鱼是不会反射光线所以周围没有光晕?

之后做实验我会考虑到您说的这些注意事项,确实是很聪明且有道理的一些建议,谢谢您。

其实我是计算机专业的学生,我更偏向从计算机的角度去思考这些问题,所以我没有考虑过lightroom,之前我使用opencv-python去处理我发给您的那张实验测试图像,但是我发现可能是一开始做实验就有问题,所以导致我处理测试图像也没有处理好。您说的分离RGB三个通道的操作,我也尝试过,确实是可以明显看出绿色通道对于我的实验图有很好的转换(从彩色图像到灰度图像) 但是还是很难达到像您那样完美的实验,把鱼身为白色和黑色的背景完美分开。(无论是从视频还是单纯的图片去看,您的实验都堪称是完美的实验)。

cheers, 郑博文

Mrzhengbowen commented 2 years ago

珊瑚鱼PIV2_Moment B00001 还是很明显看出珊瑚鲶鱼视频中鱼体周围的光晕的,但是脚本示例中的鱼体周围没有,见附图。

Nils-Tack commented 2 years ago

Hello, So in the video, you may think that I am using visible light because you can see the particles, the fish, and some scattering of the light. But the thing is that I was using a camera capable of seeing infrared light. This is in part why my videos are originally gray scale images (although technically the output images contain the 3 RGB channels). Infrared only shows as different hues of gray. Why using infrared lasers, you may ask? Well, most animals, including fish, tend to be very sensitive to bright lights in the visible spectrum. After countless experiments, I noticed that using regular green laser had a slight tendency to affect their behavior, and consequently this influenced the quality of my experimental results. After switching to infrared, I no longer had issues with my fish reacting to the lasers. If you are ever considering using IR lasers, there are a couple minor downsides that you will have to take into account: 1) IR (or technically near-IR) light is invisible to us. Therefore, aligning two opposing overlapping laser sheets perfectly rapidly becomes a challenge. But if like me, you mount the two laser on the same platform, then you can move your laser sheet up and down as you please without fear of having to realign everything (see attached picture); 2) IR light dissipates very quickly in water. In fact, this dissipation occurs so quickly that one of my lasers had to go to full power on the side of the swim tunnel/buffer tank where I had about 30cm of water to go through, while for the other side (<10 cm of water) I could get away with using only 2/3 of the power.

When it comes to your setup, you are limited by the available equipment, and this is totally fine. In fact, using an iPhone is not the worst thing in the world. However, unlike traditional cameras (or the more expensive high-speed cameras that I am using), you have little control over very important parameters like shutter speed, aperture, ISO, and the overall exposure of the scene. As a result, this may generate just enough noise that it starts affecting your particle field. As for the blackout material, it sounds intuitive to put it on the outside of the tank to obtain a black background. However, one intrinsic property of a square, glass container like a tank is to reflect light like crazy and to scatter light. In this case, placing your blackout material outside the tank would not help at all. I would recommend putting blackout material inside the tank, to line the glass walls and avoid any parasitic reflection. I did this with our flume, and once again, results started improving rapidly. The catfish did not benefit from this modification, but the mojarras did. And the difference is pretty obvious here. I used some sort of powder-coated aluminum foil from Thor Labs (BKF12), but in all fairness, any matte black material can do. I have experimented with the walls and lids of black storage containers and trash cans and the results weren’t too bad. You may want to consider a similar option since your tank is, relatively speaking, small and any light coming from the illuminated particles will be reflected by the nearby wall and generate parasitic light scattering.

As to the halo around the catfish, several things happened here, among which better experimental design improved things a bit. As mentioned in my previous post, for some reason, the skin of my coral catfish scattered light way more than any other fish that I ever put in this flume. I believe that, unlike mojarras that possess large ctenoid scales, this was a result of their smooth skin. Secondly, for the Mojarras, I added the blackout material inside the tank to mitigate internal reflection and light scattering. This greatly improved the quality of the videos. But in all fairness, the mojarras also ended up being far less reflective (counterintuitively). When it comes to designing PIV experiments, there is always some major troubleshooting with the initial experiments, and later with image processing. It took me many trials, and many mistakes were made along the way to come up with something that worked reliably and consistently with our swim tunnel. Somehow, IR light turned out to be a bit more difficult to work with than our green lasers. Although I never quantified the difference, I always had the impression that IR scattered more than green light when doing PIV, and the perfect seeding density to avoid too much scattering was much more difficult to achieve than with green light. But collimating the beam to produce a very thin laser sheet seemed to solve a lot of the issues involving the use of IR lasers.

Cheers,

Nils Flume setup-01

Mrzhengbowen commented 2 years ago

hi, 原来如此,您的实验场景真的是令我惊叹,做的真的是太好了。我到现在才真正的明白您的实验设置、场景和注意事项,之后我也会用红外光来进行实验,在基于之前的实验进行对比。同时,我也会更新我的实验装置,以达到更好的实验结果。

还有一个问题想问,就是您的脚本示例图片,画圈的部分哪个是尾巴呢?这不是没有经过matlab处理的原始图片吗? Sketch004

Mrzhengbowen commented 2 years ago

InkedB00001_LI

Mrzhengbowen commented 2 years ago

hi, Nils博士,您认为BWmask和outline的关系是什么呢?对于计算鱼体近体速度场有必要提取鱼体的轮廓吗?

在传统的实验中,我们把原始灰度图像进行一系列处理得到BWmask,在把BWmask当做原始灰度图像的mask后得到最终我们想要得到的piv图像。(见附图1),之后在通过对原始图像进行速度场的检测后得到速度场图像,再把速度场叠加在最终得到的piv图像上(图2)。

在您的实验中,您也是对原始图像进行的压力场测试吗(图3)?然后再将压力场叠加在BWmask上?还是将压力场叠加在鱼体轮廓图上?

1截图20220503192739 2截图20220503193413 3 截图20220503193800

cheers,

zhengbowen

Nils-Tack commented 2 years ago

Hi, Thank you very much for your previous comment. I indeed try to make sure that the experimental set up is as good as possible to avoid 1) having to re-run experiments because it is not good enough, 2) having to write case-specific scripts and deal with the complicated troubleshooting that comes with it. Regarding the image, the tail would be the inferior circle. The superior circle that you highlighted is the dorsal fin. I did not provide all the details about this shot necessarily, but in reality; the laser sheet is not centered exactly on the rostro-caudal axis. The laser illuminates the plane that roughly intersects the top half of the superior caudal fin (see image). This is why in many cases I had to make slight local adjustments to the contrast and brightness to make sure that I had all the body parts included in the mask. Figure S0 - Flume setup-05

Mrzhengbowen commented 2 years ago

喔喔!我了解了,所以您也制作了一个mask把鱼体包含进去

Nils-Tack commented 2 years ago

Hi, Strictly speaking, when it comes to the masks and outlines, the BW masks are not necessary. They used to be an intermediate step to easily create the outlines that are required to run the pressure script (using the matlab’s bwboundaries function). In reality, you could eliminate the export of all the BW images to instead directly export the outlines. But, and you did the right thing when going with BW masks, BW masks can be very useful. I kept them for a few reasons: 1) in the event that you have a few bad masks created during the automated masking of the fish, you can very easily find them just by scrolling down the folder that contains all your images. There is no need to import anything into matlab just to check a few images; 2) given that I am also very interested in kinematics parameters such tailbeat frequency, amplitude, wave period, body lateral displacement… having simple binary figures helps tremendously. For instance, they can be reused for many other reasons like extracting the centerline of the fish via the skeletonize function in matlab. Trying to do this with x-y coordinates with the outlines is either way more complicated than necessary, or you would have to convert those x-y outlines to a binary image to then quickly extract the centerline using the skeletonize function discussed above. In the end, those BW masks ended up being useful again; 3) If you want or need to make a few illustrative videos of basic fish swimming (or at least to show the motion), then you already have simplified images to do just this.

However, to answer your specific question regarding the use of outlines (in the form of x and y coordinates), they are necessary to compute pressure fields and they make life so much easier when making figures. You will often see people mention that they computed velocity fields using masks (I assume BW) to avoid artefacts caused by the detection of the body of the animal rather than the fluid. However, if (and only if), the spacing between your vectors is about the same as the dilation of your mask/outline around the body of the fish (see the read me file that I created for additional details) then I don’t find it necessary and in fact I have never really noticed any real difference (at least at the scale I am working with). The reason I mention the dilation of the mask by a few pixels is because we want to avoid the undesirable effects of considering the boundary layer when computing pressures (see Lucas et al. 2017). If I meet all these assumptions, I generally use the outlines (in x-y format) to remove the unwanted vectors located on the body of the fish and right on the surface of the fish after PIV processing. In short, I often compute velocity fields without a mask, and eliminate the vectors that fall on the body of the fish and on its surface (+ a small distance from the edges to avoid the boundary layer and the stray vectors often generated during computation). By doing this, I effectively generate a boundary in my velocity fields without the need to worry about masking when computing PIV data. But once again, the assumptions discussed above must be met to do this safely and reliably. From there, I can reliably compute vorticity (using matlab’s curl function) and overlay a clean x-y outline on top. I also do the same for the pressure fields since pressure fields are returned in the same unit as your PIV, which was used to create x-y outlines. Now you should see the interconnection between all these things and how versatile these x-y outlines are compared with BW masks when plotting. If you prefer, you can also plot the original grayscale image with the velocity/vorticity/pressure fields overlayed on it, minus the body of the fish (see the short video that I made https://www.youtube.com/watch?v=NXg7IEBQGWY).

Your approach to make the BW mask and plot your velocity vectors is quite good, and the quality of your masks and PIV is rather excellent. Technically, using the BW mask to extract the grayscale image of your fish is not a bad approach. However, the advantage of creating x-y outlines is that you can apply very effective, and yet simple, smoothing options to get rid of the jagged edges. Although rough edges are not too big of an issue in general, in the past I have seen some artefacts in the pressure fields that were caused by slightly irregular masks of the tail of my fish. Plus, I find it easier to get rid of the null vectors that still show on the surface of the fish when plotting by simply using the very fast ‘inpolygon’ function in matlab to exclude those vectors (for which you should have x and y coordinates) that fall within the boundary formed by the outline (also defined in the same x-y units used to create your vectors). This is a little different from your approach, but the outcome is not very different in the end. However, you must generate x-y outlines to run the pressure script. This script was not originally developed to read-in BW images and extract the outlines. If you do not want to deal with making outlines, you can probably make a quick edit of the Queen2 source code to read in BW images and apply the proper scale from your PIV data. Personally, I find this process a little inefficient since you would have to define your scale several times when you plot data, and then when you run queen 2. Creating x-y outlines solves all your issues with defining a scale since they take the same units as your PIV and pressure data. This greatly simplifies plotting all your data (velocity/vorticity/pressure fields) when making figures since scaling an image is no longer an issue.

So in summary, you approach is not incorrect, and in fact it seems to work well. However, I would recommend you create outlines since they take barely any time to make, they allow you to very easily smooth your masks, and they are required to run the pressure script. Also, they solve all the potential issues of always having to deal with a scale when making figures. I personally rarely plot figures with the raw image in the background unless it is necessary to properly show the reader what is happening in the frame. In my case it is straight forward since I mostly care about movements of the body from above and on occasions, motions of the pectoral fins. In this context, if you have the outlines available, you can simply patch a simple black (or whatever color of your choice) mask on top of your velocity/vorticity/pressure fields (see attached picture). It is nice, clean, and very easy to interpret. However, in your case, it may help to use the raw image to better understand the orientation of the fish and to better visualize its fins.

I hope that this sheds a bit more light on the way I process my data and plot it to make figures.

Cheers,

Nils

outnile explanation-01