Reptillian Posted May 9, 2020 Posted May 9, 2020 (edited) I have decided to attempt to convert another one of my gmic-qt filter to a pdn plugin, and part of it is converting non-zero alpha pixels count per column or row. That means a vector of size that is dependent one of the dimension within the image, and each number correspond to the number of non-alpha pixels. For clarification on what I'd like to convert, if needed, this is the code I'm translating to c# - #@cli rep_sptbwgp: (eq. to rep_shift_pixel_to_boundary_with_group_pixels) rep_sptbwgp: rep_shift_pixel_to_boundary_with_group_pixels $* #@cli rep_shift_pixel_to_boundary_with_group_pixels: -1<=_position<=1, _axis={ 0=Horizontal | 1=Vertical }, 0<=_influence_factor<=1, _threshold>=0,_channel_mode #@cli : Shifts pixels to boundary by percentage using grouped pixels. position less than .5 means shift will be negative, and position greater than .5 means shift will be positive. #@cli : Assign an argument to _channel_mode if you want to disable restricting effect on alpha channel or avoid manipulating 4 channels image in case of CMYKA image. Only use in rare cases! #@cli : Default values: '_position=-1','_axis=1','_influence_factor=1','_threshold=0','_channel_mode=' rep_shift_pixel_to_boundary_with_group_pixels: skip ${1=-1},${2=1},${3=.5},${4=0},${5=} any_channels=0 tcr=3 influence_factor={min(abs($3),1)} position={(($1+1)/2)} if $position<0 position=0 elif $position>1 position=1 fi if narg($5) if $5>=0 tcr+=1 else any_channels=1 fi fi if $influence_factor #Apply effect is non-zero alpha# repeat $! l[$>] if (s==2||s>$tcr)||$any_channels ss={s-1} sh $ss f. "i>$4?i:0" rm. #If alpha is less than _threshold, then it converts to 0# {w},{h},1,1,i(#-1,x,y,0,$ss)?1 #Create a new surface where all non-zero alpha is 1. Otherwise, 0. Used for sum later.# if $2 {w},1,1,1,sum(crop(#-1,x,0,0,0,1,h#-1,1,1)) #Create a strip of vector containing number of non-zero alpha within row or column# {w#-2},{h#-2},1,{$ss+1},if(i(#-1,x,0,0,0)==h#0,i(#0)) #Copy all row or column where the number of non-zero alpha is equal to the respective dimension# else 1,{h},1,1,sum(crop(#-1,0,y,0,0,w#-1,1,1,1)) #Create a strip of vector containing number of non-zero alpha within row or column# {w#-2},{h#-2},1,{$ss+1},if(i(#-1,0,y,0,0)==w#0,i(#0)) #Copy all row or column where the number of non-zero alpha is equal to the respective dimension# fi eval ${-math_lib}" influence_factor="$influence_factor"; invert_factor=1-influence_factor; position="$position"; if($2, for(xx=0,xx<w#-1,xx++, nyy=h#-1-1; if(i(#-2,xx,0)&&i(#-2,xx,0)<h#-1, N=i(#-2,xx,0); tyy=h#-1-N; nyy-=tyy*position; for(yy=h#-1-1,yy>-1,yy--, if(N, if(i(#-3,xx,yy), N--; tnyy=influence_factor*nyy+invert_factor*yy; if(position==1,I(#-1,xx,ceil(tnyy))=I(#-4,xx,yy); ,I(#-1,xx,floor(tnyy))=I(#-4,xx,yy); ); nyy--; ); ,break(); ); ); ); ); , for(yy=0,yy<h#-1,yy++, nxx=0; if(i(#-2,0,yy)&&i(#-2,0,yy)<w#-1, N=i(#-2,0,yy); txx=w#-1-N; nxx+=txx*position; for(xx=0,xx<w#-1,xx++, if(N, if(i(#-3,xx,yy), N--; tnxx=influence_factor*nxx+invert_factor*xx; if(position==1,I(#-1,floor(tnxx),yy)=I(#-4,xx,yy); ,I(#-1,ceil(tnxx),yy)=I(#-4,xx,yy); ); nxx++; ); ,break(); ); ); ); ); ); " k. fi endl done fi Edited May 9, 2020 by Reptillian Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.
MJW Posted May 9, 2020 Posted May 9, 2020 If I correctly understand the question (which I may not), you would just count and save the number of pixels with non-zero alphas in each row or column in the pre-processing step, which is PreRender() in Codelab and OnSetRenderInfo() in Visual Studio. Since it doesn't change, a flag (likely just the non-null pointer to the array where the results are saved) should be used to prevent re-doing it each time a control is changed. Quote
Reptillian Posted May 9, 2020 Author Posted May 9, 2020 5 minutes ago, MJW said: If I correctly understand the question (which I may not), you would just count and save the number of pixels with non-zero alphas in each row or column in the pre-processing step, which is PreRender() in Codelab and OnSetRenderInfo() in Visual Studio. Since it doesn't change, a flag (likely just the non-null pointer to the array where the results are saved) should be used to prevent re-doing it each time a control is changed. Most of that I get, but I would like the fastest way to create a vector of non-zero alpha counts. I suppose there's either do while or for loop method. You lost me at flag though. Explain. Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.
MJW Posted May 10, 2020 Posted May 10, 2020 It probably makes no significant difference whether a while or a for loop is used, especially when the optimizer is on for the Release version. And if it does make a difference, about the only way to know is to look at the compiled code, or run a profiler. In any case, it will be so quick it will almost certainly not matter. (I'd use a for loop.) As to the flag: OnSetRenderInfo() runs each time a control is changed, as does PreRender() (which is called from OnSetRenderInfo()). That's good, because it allows global things to be updated to take into account the new control values. However, the number of pixels in a row with non-zero alphas depends only on the state of the image at the time you run the plugin, so the count only needs to be done once. The usual way to accomplish this is to use a "first time" flag to say whether it's already been done. Since you probably need to store the results in an array, the pointer to the array is a very convenient flag. Something like this: int[] rowNonZeroAlphas = null; void PreRender(Surface dst, Surface src) { int width = src.Width, height = src.Height; if (rowNonZeroAlphas == null) { rowNonZeroAlphas = new int[height]; for (int y = 0; y < height; y++) { int nonZeroAlphaCount = 0; for (int x = 0; x < width; x++) { if (src[x, y].Alpha != 0) nonZeroAlphaCount++; } rowNonZeroAlphas[y] = nonZeroAlphaCount } } } (Please forgive any mistakes) The first time it runs, the array address will be null, so it will allocate the array and compute the results. On all subsequent times it's run, the address will be non-null, so it will skip over the computations. 1 Quote
Reptillian Posted May 10, 2020 Author Posted May 10, 2020 Ok, it seems that's all I needed to do. Thanks, I'll get to converting 'Grouped Pixel Axis-Based Shift' to a PDN plugin at some point during the next weekend. It doesn't look that hard to do. Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.
MJW Posted May 10, 2020 Posted May 10, 2020 If you need the info for both the rows and columns, the simplest way is probably: for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (src[x, y].Alpha != 0) { columnNonZeroAlphas[x]++; rowNonZeroAlphas[y]++; } } } There are probably slightly more efficient ways, but since it only runs once, and doesn't do anything too complex, it's probably plenty efficient enough. (You don't need to first zero the arrays, since C# zeroes numeric arrays when they're allocated.) Quote
Reptillian Posted May 10, 2020 Author Posted May 10, 2020 (edited) 2 hours ago, MJW said: If you need the info for both the rows and columns, the simplest way is probably: for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (src[x, y].Alpha != 0) { columnNonZeroAlphas[x]++; rowNonZeroAlphas[y]++; } } } There are probably slightly more efficient ways, but since it only runs once, and doesn't do anything too complex, it's probably plenty efficient enough. (You don't need to first zero the arrays, since C# zeroes numeric arrays when they're allocated.) The columnnonzeroalpha[x]++ is something I would have never thought off for generic scripting/programming. Thank you. Edited May 10, 2020 by Reptillian Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.
Reptillian Posted May 12, 2020 Author Posted May 12, 2020 (edited) Um, I am getting a error here. Otherwise, code looks pretty much correct if you look at the reference code. EDIT: I am getting it to work it seems, just very buggy. // Name: Shifted Group Pixel to Boundary // Submenu: // Author: // Title: // Version: // Desc: // Keywords: // URL: // Help: #region UICode DoubleSliderControl positionperc = -100; // [-100,100] Position of Pixels (%) DoubleSliderControl influenceperc = 100; // [0,100] Influence Factor (%) IntSliderControl alpha_threshold = 1; // [1,255] Alpha Threshold ListBoxControl axis = 0; // Axis|Horizontal|Vertical #endregion int[] columnNonZeroAlphas = null; int[] rowNonZeroAlphas = null; void PreRender(Surface src) { int width = src.Width, height = src.Height; if (rowNonZeroAlphas == null) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (src[x,y].A >= alpha_threshold) { columnNonZeroAlphas[x]++; rowNonZeroAlphas[y]++; } } } } } void Render(Surface dst, Surface src, Rectangle rect) { double position = (positionperc / 100 + 1) / 2; double influence_factor = influenceperc / 100; double invert_factor = 1 - influence_factor; int width = rect.Right; int height = rect.Bottom; int txx,tyy,nxx,nyy,fx,fy,N; double tnyy,tnxx; if (axis==0) { for (int x = 0; x < rect.Right; x++) { nyy = height - 1; if (columnNonZeroAlphas[x] != 0) { N=columnNonZeroAlphas[x]; tyy = height - N ; nyy-=(int)(tyy*position); for (int y = height - 1; y > - 1; y++) { if (N != 0) { if (src[x,y].A >= alpha_threshold) { N--; tnyy = influence_factor * (double)(nyy) + invert_factor*(double)(y); if (position == 1) { fy=(int)(Math.Ceiling(tnyy)); } else { fy=(int)(Math.Floor(tnyy)); } dst[x,y] = src[x,fy]; nyy--; } } else { break; } } } } } else { for (int y = rect.Top; y < rect.Bottom; y++) { nxx = 0; if (rowNonZeroAlphas[y] != 0) { N=rowNonZeroAlphas[y]; txx = width - N; nxx+=(int)(txx*(position)); for (int x = 0; x < rect.Right; x++) { if (N != 0) { if (src[x,y].A >= alpha_threshold) { N--; tnxx = influence_factor * (double)(nxx) + invert_factor*(double)(x); if (position == 1) { fx=(int)(Math.Floor(tnxx)); } else { fx=(int)(Math.Ceiling(tnxx)); } dst[x,y] = src[fx,y]; nxx++; } } else { break; } } } } } } Edited May 12, 2020 by Reptillian Better match to g'mic-qt rep_sptbwgp source code ; Still not there... Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.
Reptillian Posted May 12, 2020 Author Posted May 12, 2020 (edited) It's coming along! // Name: Shifted Group Pixel to Boundary // Submenu: // Author: // Title: // Version: // Desc: // Keywords: // URL: // Help: #region UICode DoubleSliderControl positionperc = -100; // [-100,100] Position of Pixels (%) DoubleSliderControl influenceperc = 100; // [0,100] Influence Factor (%) IntSliderControl alpha_threshold = 255; // [1,255] Alpha Threshold ListBoxControl axis = 1; // Axis|Horizontal|Vertical #endregion void Render(Surface dst, Surface src, Rectangle rect) { double position = (positionperc / 100 + 1) / 2; double influence_factor = influenceperc / 100; double invert_factor = 1 - influence_factor; int w = rect.Right; int h = rect.Bottom; int tx,ty,nx,ny,fx,fy,N; double tny,tnx; int[] columnNonZeroAlphas = new int[w]; int[] rowNonZeroAlphas = new int[h]; if (axis==1) { for (int x = 0; x < w; x++) { int nonZeroAlphaCount = 0; for (int y = 0; y < h; y++) { if (src[x,y].A >= alpha_threshold) {nonZeroAlphaCount++;} columnNonZeroAlphas[x] = nonZeroAlphaCount; dst[x,y]=ColorBgra.FromBgra(0,0,0,0); } } } else { for (int y = 0; y < h; y++) { int nonZeroAlphaCount = 0; for (int x = 0; x < w; x++) { if (src[x,y].A >= alpha_threshold) {nonZeroAlphaCount++;} rowNonZeroAlphas[y] = nonZeroAlphaCount; dst[x,y]=ColorBgra.FromBgra(0,0,0,0); } } } if (axis==1) { for (int x = 0; x < w; x++) { if (IsCancelRequested) return; ny = h - 1; if (columnNonZeroAlphas[x] != 0) { N=columnNonZeroAlphas[x]; ty = h - N ; ny-=(int)(ty*position); for (int y = h - 1; y >= 0; y--) { if (N != 0) { if (src[x,y].A >= alpha_threshold) { tny = influence_factor * (double)(ny) + invert_factor*(double)(y); if (position == 1) { fy=(int)(Math.Ceiling(tny)); } else { fy=(int)(Math.Floor(tny)); } N--; dst[x,fy] = src[x,y]; ny--; } } else {break;} } } } } else { for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; nx = 0; if (rowNonZeroAlphas[y] != 0) { N=rowNonZeroAlphas[y]; tx = w - N; nx+=(int)(tx*(position)); for (int x = 0; x < rect.Right; x++) { if (N != 0) { if (src[x,y].A >= alpha_threshold) { tnx = influence_factor * (double)(nx) + invert_factor*(double)(x); if (position == 1) { fx=(int)(Math.Floor(tnx)); } else { fx=(int)(Math.Ceiling(tnx)); } N--; dst[fx,y] = src[x,y]; nx++; } } else {break;} } } } } } Edited May 12, 2020 by Reptillian Quote G'MIC Filter Developer I am away from this forum for undetermined amount of time: If you really need anything related to my PDN plugin or my G'MIC filter within G'MIC plugin, then you can contact me via Paint.NET discord, and mention me.
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.