<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>开源 | 卢子期</title><link>https://assassin-plus.github.io/portfolio/zh/tags/%E5%BC%80%E6%BA%90/</link><atom:link href="https://assassin-plus.github.io/portfolio/zh/tags/%E5%BC%80%E6%BA%90/index.xml" rel="self" type="application/rss+xml"/><description>开源</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>zh-Hans</language><lastBuildDate>Tue, 12 Dec 2023 00:00:00 +0000</lastBuildDate><image><url>https://assassin-plus.github.io/portfolio/media/icon_hu_982c5d63a71b2961.png</url><title>开源</title><link>https://assassin-plus.github.io/portfolio/zh/tags/%E5%BC%80%E6%BA%90/</link></image><item><title>Intro 2 CUDA</title><link>https://assassin-plus.github.io/portfolio/zh/post/intro2cuda/</link><pubDate>Tue, 12 Dec 2023 00:00:00 +0000</pubDate><guid>https://assassin-plus.github.io/portfolio/zh/post/intro2cuda/</guid><description>&lt;h1 id="intro-2-cuda"&gt;Intro 2 CUDA&lt;/h1&gt;
&lt;h2 id="streams"&gt;Streams&lt;/h2&gt;
&lt;h3 id="page-locked-host-memory"&gt;Page-Locked Host Memory&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostAlloc((void**)&amp;amp;a, N*sizeof(int), cudaHostAllocDefault);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaFreeHost(a);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;page-locked / pinned host memory:
os guarantees that the memory is resident in physical memory and won&amp;rsquo;t be paged out to disk.&lt;/p&gt;
&lt;p&gt;simultaneously pinned memory opt out of the feature of virtual memory.&lt;/p&gt;
&lt;h3 id="multiple-streams"&gt;Multiple Streams&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStream_t stream1, stream2;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamCreate(&amp;amp;stream1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamCreate(&amp;amp;stream2);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaMemcpyAsync(d_a, a, N*sizeof(int), cudaMemcpyHostToDevice, stream1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaMemcpyAsync(d_b, b, N*sizeof(int), cudaMemcpyHostToDevice, stream2);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kernel&amp;lt;&amp;lt;&amp;lt;grid1, block1, 0, stream1&amp;gt;&amp;gt;&amp;gt;(d_a, N);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kernel&amp;lt;&amp;lt;&amp;lt;grid2, block2, 0, stream2&amp;gt;&amp;gt;&amp;gt;(d_b, N);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamSynchronize(stream1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamSynchronize(stream2);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamDestroy(stream1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamDestroy(stream2);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="gpu-work-schedule"&gt;GPU Work Schedule&lt;/h3&gt;
&lt;p&gt;Be aware of the GPU work schedule.
There are different execution units to execute different types of instructions, such as copy, compute, and so on.
And &lt;strong&gt;the order of code dependencies is equal to the order written in the code&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="multi-gpu"&gt;Multi-GPU&lt;/h2&gt;
&lt;h3 id="zero-copy-host-memory"&gt;Zero-Copy Host Memory&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostAlloc((void**)&amp;amp;a, N*sizeof(int), cudaHostAllocWriteCombined | cudaHostAllocMapped);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;cudaHostAllocWriteCombined: this flag indicates that the runtime should allocate the buffer as write-combined, which will not change functionality in application
but represents a performance enhancement for buffers that will be read only by the GPU.&lt;/p&gt;
&lt;p&gt;Write-combined memory can be extremely inefficient in scenarios where CPU also needs to perform reads from the buffer.&lt;/p&gt;
&lt;p&gt;cudaHostAllocMapped: the buffers can be accessed from the GPU. However, since there is a difference between the virtual address space of the CPU and the GPU,
the call to cudaHostAlloc() will return a CPU pointer, which is then mapped to a GPU pointer using cudaHostGetDevicePointer().&lt;/p&gt;
&lt;h3 id="portable-pinned-memory"&gt;Portable Pinned Memory&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;This is neccesary when you use multiple GPUs.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostAlloc((void**)&amp;amp;a, N*sizeof(int), cudaHostAllocPortable);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When a buffer is allocated as pinned, they will only &lt;strong&gt;appear&lt;/strong&gt; page-locked to the thread that allocated them. If another thread tries to access the buffer, they will see the buffer as standard pageable memory.&lt;/p&gt;
&lt;p&gt;To support portable pinned memory and zero-copy memory in multi-GPU systems, the code need two notable changes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;deviceID&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;cudaSetDevice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;deviceID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;cudaSetDeviceFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cudaDeviceMapHost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We need a call to cudaSetDevice() to enable every thread controls a different GPU.&lt;/p&gt;
&lt;p&gt;In addition, as we use zero-copy in order to access these buffers directly from the GPU, we use cudaHostGetDevicePointer() to get the valid device pointers for the host memory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;float *a, *b, *partial_c;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;float *dev_a, *dev_b, *dev_partial_c;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//allocate memory on the CPU side
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a = data-&amp;gt;a;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;b = data-&amp;gt;b;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;partial_c = (float *)malloc(blocksPerGrid *　sizeof(float));
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostGetDevicePointer(&amp;amp;dev_a, a, 0);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostGetDevicePointer(&amp;amp;dev_b, b, 0);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaMalloc((void**)&amp;amp;dev_partial_c, blocksPerGrid * sizeof(float));
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dev_a += data-&amp;gt;offset;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dev_b += data-&amp;gt;offset;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kernel&amp;lt;&amp;lt;&amp;lt;blocksPerGrid, threadsPerBlock&amp;gt;&amp;gt;&amp;gt;(dev_a, dev_b, dev_partial_c);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Contrast Adjustments</title><link>https://assassin-plus.github.io/portfolio/zh/post/color-grading/</link><pubDate>Thu, 27 Jul 2023 00:00:00 +0000</pubDate><guid>https://assassin-plus.github.io/portfolio/zh/post/color-grading/</guid><description>&lt;h1 id="调整反差的工具"&gt;调整反差的工具&lt;/h1&gt;
&lt;p&gt;LIFT GAMMA GAIN&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lift: 调整趾部&lt;/li&gt;
&lt;li&gt;Gamma：更改中间调的分布&lt;/li&gt;
&lt;li&gt;Gain：调整高光&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contrast &amp;amp; Pivot&lt;/p&gt;
&lt;p&gt;Contrast：线性地改变图像的黑白位
Pivot：分配Contrast在黑位白位之间区域的权重&lt;/p&gt;
&lt;h2 id="ycbcrrgb下的luma调整"&gt;Y&amp;rsquo;CbCr/RGB下的LUMA调整&lt;/h2&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;大多数调色系统的一级反差控制使用RGB图像处理方式，即调整图像亮度时，是对所有三个色彩分量进行等量且同步调整的。由此产生的调整，会对图像饱和度产生明显影响。
单独操控Y&amp;rsquo;CbCr的Y通道，对图像的饱和度没有可测量的效果（即矢量波形保持不变）。然而，图像的感知饱和度确实有改变。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id="用log调色控件微调反差"&gt;用LOG调色控件微调反差&lt;/h1&gt;
&lt;h2 id="使用offsetexposure和contarst微调反差"&gt;使用OFFSET、EXPOSURE和CONTARST微调反差&lt;/h2&gt;
&lt;p&gt;在套用LUT之前使用这些控件！
这样可以控制图像反差并找回一些图像细节，因为可能在套用LUT时会被裁切&lt;/p&gt;
&lt;h2 id="使用shadowmidtone和highlight微调反差"&gt;使用SHADOW、MIDTONE和HIGHLIGHT微调反差&lt;/h2&gt;
&lt;p&gt;他们被设计为用于log素材正常化之前的调整&lt;/p&gt;
&lt;p&gt;这些控件对图像的影响完全取决于图像本身有多少反差。
Shadow：影响影调的底部三分之一
Midtone：影响范围广泛的中间调
Highlight：影响高光的顶部三分之一&lt;/p&gt;
&lt;h1 id="设置适当的高光和暗部"&gt;设置适当的高光和暗部&lt;/h1&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;对高光的感知与阴影的深度有关。某些时候压低阴影而高光保留不动比提高高光更好。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="保持中间调的同时将白位合法化"&gt;保持中间调的同时将白位合法化&lt;/h2&gt;
&lt;p&gt;压低Gain的同时将中间调提高以补偿影响，也可以通过降低一点暗部来保持反差。&lt;/p&gt;
&lt;h2 id="尝试用降低中间调替代压低暗部的操作"&gt;尝试用降低中间调替代压低暗部的操作&lt;/h2&gt;
&lt;p&gt;不是每个图像都要求把暗部压到0%，有时候降低中间调可以达到相同的效果。&lt;/p&gt;
&lt;h1 id="反差和视觉感知"&gt;反差和视觉感知&lt;/h1&gt;
&lt;h2 id="利用环境效应"&gt;利用环境效应&lt;/h2&gt;
&lt;p&gt;提高高光令阴影看起来更暗，同时尽量避免平均中间调看起来比原来更亮。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提高Gain&lt;/li&gt;
&lt;li&gt;为了减少图像的感知亮度，降低Gamma。这导致高光减少了一点，但是上步中提起高光幅度很大，不会有太大影响&lt;/li&gt;
&lt;li&gt;降低中间调的同时阴影降低的有点太多，提高Lift作为补偿&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="增加图像感知锐度"&gt;增加图像感知锐度&lt;/h2&gt;
&lt;p&gt;调整反差的另一个效应：增加对比度可以让画面细节变得更锐。&lt;/p&gt;
&lt;h1 id="如何处理曝光问题素材"&gt;如何处理曝光问题素材&lt;/h1&gt;
&lt;h2 id="曝光不足"&gt;曝光不足&lt;/h2&gt;
&lt;p&gt;试图增加亮度和中间调时，通常：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;会增加噪点&lt;/li&gt;
&lt;li&gt;饱和度过高/欠饱和&lt;/li&gt;
&lt;li&gt;暗部细节不足&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;提高中间调比调整白位更好&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;使用曲线控制器，将中间调偏低区域伸展，同时保持中间调偏上的区域不变以获得扎实的阴影。&lt;/p&gt;
&lt;h2 id="过曝"&gt;过曝&lt;/h2&gt;
&lt;p&gt;先做取舍：是否需要压过曝部分&lt;/p&gt;
&lt;p&gt;如果过曝面积不太大：&lt;/p&gt;
&lt;h3 id="为过曝区域添加颜色"&gt;为过曝区域添加颜色&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;降低Gain，将高光合法化&lt;/li&gt;
&lt;li&gt;如果有需要，用Gamma提高中间调&lt;/li&gt;
&lt;li&gt;使用HSL选色的Luma控件&lt;/li&gt;
&lt;li&gt;将Gain推向某种颜色，即补色&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="为过曝区域添加辉光"&gt;为过曝区域添加辉光&lt;/h3&gt;
&lt;p&gt;若夸张的过曝不能避免，光晕和溢出可以软化过渡区域的边缘，也能让画面更加舒服&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;降低Gain，将高光合法化，同时提高Gamma补偿&lt;/li&gt;
&lt;li&gt;使用HSL选色的Luma控件分离出过曝区域&lt;/li&gt;
&lt;li&gt;使用HSL选色中的Blur或Soften，模糊键控蒙版，最终要令蒙版比曝光过度的区域更大，边缘更柔软&lt;/li&gt;
&lt;li&gt;用Lift或Gamma来提亮选中的键控区域，类似晕染和溢出会逐渐出现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="使用通道混合器重建被裁切的通道"&gt;使用通道混合器重建被裁切的通道&lt;/h3&gt;
&lt;p&gt;由于显著过曝而造成的某个通道分配不均，导致难看的图像高光。检查RGB分量示波器，如果某个通道远高于110%，但是其他通道都没有，那么可以使用这类方法。&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;这是最后的方法，目的是找回更多图像数据而不是让图像更漂亮。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;调整色彩和反差，达到色彩平衡（一级校色），先别担心裁切位置，只需要进行整体校正。在这种情况下，offset来重新编排三个色彩通道的位置，先降低红色通道，再使用“Master Offset”来降低整体图像信号，使图像阴影密度更多&lt;/li&gt;
&lt;li&gt;创建新节点进行通道修复。这次调整所作的校正将要放在之前的校正上。也即使用Layer Mixer&lt;/li&gt;
&lt;li&gt;选择新节点，检查哪个通道在被裁切的区域内有更多的细节。&lt;/li&gt;
&lt;li&gt;使用 RGB Mixer / Channel Blending / Channel isolation / Blend mode来混和绿色与蓝色通道给红色通道。&lt;/li&gt;
&lt;li&gt;使用Luma限定控件分离出过曝高光区域，然后柔化边缘并使用该键控蒙版来限制通道混合的影响范围。&lt;/li&gt;
&lt;li&gt;最后添加额外的校色操作，整体图像进行调色&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>