MJW Posted May 27, 2015 Share Posted May 27, 2015 This is a plugin intended to help remove the backgrounds from images. I wasn't sure where to put it, but decided to make it an Adjustment. The controls are: Match Color is normally the color to be erased, but it can optionally be the color to keep. It can be either the User Match Color, or the Primary or Secondary Color. User Match Color is the Match Color when User Match Color is specified. Hue Tolerance determines how closely the pixel's hue must match the Match Color's hue. Saturation Tolerance determines how closely the pixel's saturation must match the Match Color's saturation. Value Tolerance determines how closely the pixel's value must match the Match Color's value. RGB Tolerance specifies the maximum allowed Euclidean distance between the pixel's RGB color and the Match Color's RGB color. Gray Upper Limit (S×V) specifies the threshold for product of the saturation and value below which the Match Color or pixel's color will be classified as gray. Gray does not match any hue except gray, unless the Gray Matches All Hues option is selected. Portion of Non-Erased Color to Preserve determines how much of the "non-erased" color should remain in the pixel. The color and alpha of the pixel are adjusted to account for the degree to which the pixel color matches the Match Color. Specifically (assuming the Match Color is being erased), the color is adjusted so that the alpha is as small as possible while keeping the same color if the pixel is alpha-blended into a Match Color background layer. This can be used to achieve a softer edge. Though its not really intended to be used when the Erase Non-Matching Pixels option is selected, it does work. The erased pixels will all be the Match Color, with appropriate alphas. The value can range from 0, to entirely erase the matching pixel, to 1, to preserve as much of the pixel's color as possible. Normally, it will probably be either 0 or 1. Gray Matches All Hues specifies that colors classified as gray match all hues. Erase Non-Matching Pixels specifies that matching pixels are kept and non-matching pixels are erased. Here is the source: Spoiler // Author: MJW // Name: HSV Eraser // Title: HSV Eraser // Desc: Erase pixels of selected HSV value. // Keywords: HSV erase #region UICode byte Amount1 = 0; // Match Color|User Match Color|Primary Color|Secondary Color ColorBgra Amount2 = ColorBgra.FromBgr(0,0,0); // User Match Color double Amount3 = 0.1; // [0,1] Hue Tolerance double Amount4 = 1; // [0,1] Saturation Tolerance double Amount5 = 1; // [0,1] Value Tolerance double Amount6 = 1; // [0,1] RGB Tolerance double Amount7 = 0.15; // [0,1] Gray Upper Limit (S×V) double Amount8 = 0; // [0,1] Portion of Non-Erased Color to Preserve bool Amount9 = false; // [0,1] Gray Matches All Hues bool Amount10 = false; // [0,1] Erase Non-Matching Pixels #endregion ColorBgra matchColor; double matchB, matchG, matchR; double preserve; // Here is the main render loop function void Render(Surface dst, Surface src, Rectangle rect) { const double rgbDistScale = 3.0 * 255.0 * 255.0; int miB, miG, miR; double h, s, v; int dist2RGB; double matchH, matchS, matchV, tolH, tolS, tolV, limitGray; int tol2RGB; bool matchIsGray, pixelIsGray; bool grayMatchesAll = Amount9; bool invertErase = Amount10; preserve = Amount8; bool preservePortion = (preserve != 0.0); // Get hue to erase. if (Amount1 == 0) matchColor = Amount2; else if (Amount1 == 1) matchColor = (ColorBgra)EnvironmentParameters.PrimaryColor; else matchColor = (ColorBgra)EnvironmentParameters.SecondaryColor; matchB = miB = matchColor.B; matchG = miG = matchColor.G; matchR = miR = matchColor.R; RGBtoHSV(ref matchColor, out matchH, out matchS, out matchV); limitGray = Amount7; matchIsGray = (matchV * matchS <= limitGray); tolH = 0.5 * Amount3; tolS = Amount4; tolV = Amount5; tol2RGB = (int)(rgbDistScale * Amount6 * Amount6 + 0.5); for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { ColorBgra pixel = src[x, y]; if (pixel.A == 0) { // Just pass through transparent pixels dst[x, y] = pixel; continue; } RGBtoHSV(ref pixel, out h, out s, out v); pixelIsGray = (s * v <= limitGray); bool hueMatches; if (pixelIsGray || matchIsGray) { hueMatches = grayMatchesAll || (pixelIsGray && matchIsGray); } else { double distH = Math.Abs(h - matchH); if (distH > 0.5) // Handle color wheel wrap-around. distH = 1.0 - distH; hueMatches = (distH <= tolH); } // Also do an RGB comparison, since this is sometimes better than HSV. int distB = miB - pixel.B, distG = miG - pixel.G, distR = miR - pixel.R; dist2RGB = distB * distB + distG * distG + distR * distR; // See if pixels should be erased (or partially erased) if (invertErase ^ (hueMatches && (Math.Abs(s - matchS) <= tolS) && (Math.Abs(v - matchV) <= tolV) && (dist2RGB <= tol2RGB))) { if (!preservePortion) { // Just erase the pixel. pixel = ColorBgra.Transparent; } else { // Preserve the non-erased portion of the pixel. if (!invertErase) { pixel = RemoveColor(ref pixel); } else { // Handle the somewhat odd case. // Preserve the non-erased portion of the pixel when the // color to be erased is the non-matching color. // The remaining color will be the match color with a modified // alpha. pixel = KeepColor(ref pixel); } } } dst[x, y] = pixel; } } } // Get the color with the minimum alpha such that the source color can be // produced by alpha blending with the subtracted color. public ColorBgra RemoveColor(ref ColorBgra srcColor) { double srcB = srcColor.B, srcG = srcColor.G, srcR = srcColor.R; double alpha = RemovedAlpha(srcB, srcG, srcR); if (alpha == 0.0) { return ColorBgra.TransparentBlack; } else { double aRecip = 1.0 / alpha; int b = (int)(aRecip * (srcB - matchB) + matchB + 0.5); int g = (int)(aRecip * (srcG - matchG) + matchG + 0.5); int r = (int)(aRecip * (srcR - matchR) + matchR + 0.5); int a = (int)(alpha * preserve * (double)srcColor.A + 0.5); return ColorBgra.FromBgra((byte)b, (byte)g, (byte)r, (byte)a); } } ColorBgra KeepColor(ref ColorBgra srcColor) { double srcB = srcColor.B, srcG = srcColor.G, srcR = srcColor.R; double alpha = RemovedAlpha(srcB, srcG, srcR); // The pixel will be the erase color, and alpha will be // the complimentary alpha of the non-inverted case. byte a = (byte)(preserve * (1.0 - alpha) * (double)srcColor.A + 0.5); return matchColor.NewAlpha((byte)a); } double RemovedAlpha(double srcB, double srcG, double srcR) { return Max3(MinAlpha(srcB, matchB), MinAlpha(srcG, matchG), MinAlpha(srcR, matchR)); } // Get the minimum alpha (0 <= alpha <= 1) such that the color component // can be written as c = subC + alpha * (srcC - subC). double MinAlpha(double srcC, double subC) { if (srcC == subC) { return 0.0; } else if (srcC < subC) { return (subC - srcC) / subC; } else // (srcC > subC) { return (srcC - subC) / (255.0 - subC); } } public void RGBtoHSV(ref ColorBgra color, out double H, out double S, out double V) { RGBtoHSV(color.R, color.G, color.B, out H, out S, out V); } public void RGBtoHSV(int R, int G, int B, out double outH, out double outS, out double outV) { const double H_UNDEFINED = 0.0; // Arbitrarily set undefined hue to 0 const double recip6 = 1.0 / 6.0; // R, G, and B must range from 0 to 255 // Ouput value ranges: // outH - 0.0 to 1.0 // outS - 0.0 to 1.0 // outV - 0.0 to 1.0 double dR = (double)R / 255.0; double dG = (double)G / 255.0; double dB = (double)B / 255.0; double dmaxRGB = Max3(dR, dG, dB); double dminRGB = Min3(dR, dG, dB); double delta = dmaxRGB - dminRGB; // Set value outV = dmaxRGB; // Handle special case of V = 0 (black) if (dmaxRGB == 0) { outH = H_UNDEFINED; outS = 0.0; return; } // Handle special case of S = 0 (gray) outS = delta / dmaxRGB; if (dmaxRGB == dminRGB) { outH = H_UNDEFINED; return; } // Finally, compute hue if (dR == dmaxRGB) { outH = (dG - dB) / delta; } else if (dG == dmaxRGB) { outH = 2.0 + (dB - dR) / delta; } else //if (dB == dmaxRGB) { outH = 4.0 + (dR - dG) / delta; } outH *= recip6; outH = HueConstrain(outH); } public double Max3(double x, double y, double z) { return (x > y) ? ((x > z) ? x : z) : ((y > z) ? y : z); } public double Min3(double x, double y, double z) { return (x < y) ? ((x < z) ? x : z) : ((y < z) ? y : z); } public double HueConstrain(double MyHue) { // Makes sure that 0.0 <= MyAngle < 1.0 // Wraps around the value if its outside this range while (MyHue >= 1.0) { MyHue -= 1.0; } while (MyHue < 0.0) { MyHue += 1.0; } return MyHue; } Here is the icon: Here is the plugin: HsvEraser.zip I will happily consider any suggestions to make the interface clearer. I will also appreciate any spelling corrections. EDIT: Fixed several bugs. Changed some of the wording in the interface. Added the RGB Tolerance. Changed the version to 1.1. 1 4 Quote Link to comment Share on other sites More sharing options...
Cc4FuzzyHuggles Posted May 27, 2015 Share Posted May 27, 2015 (edited) I haven't tested the plugin out yet, but out of curiosity, is this sort of like an advanced version of Grim Color Reaper and Cut Color? It sounds like a color removing plugin that's been mixed with BoltBait's Hue/Saturation+ plugin, which is a pretty cool idea. The adjustments remind me of Hue/Saturation+, but instead of re-coloring things, it removes(erases) colors. Edited May 27, 2015 by Cc4FuzzyHuggles Quote *~ Cc4FuzzyHuggles Gallery ~* Link to comment Share on other sites More sharing options...
BoltBait Posted May 27, 2015 Share Posted May 27, 2015 The adjustments remind me of Hue/Saturation+, but instead of re-coloring things, it removes(erases) colors. My Hue/Saturation+ can erase colors by adjusting the alpha slider all the way to the left. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
MJW Posted May 27, 2015 Author Share Posted May 27, 2015 (edited) The "partial erase" feature is similar to Grim Reaper's, but I think there are significant differences between the two plugins. Grim Reaper (like, I assume, the Magic Wand) uses the RGB Euclidean distance to measure how close the colors are. For many purposes, I think HSV ranges often work better for removing backgrounds. Also, Grim Reaper reduces alpha based on the similarity of the colors. Once my program recognizes a pixel as matching, it reduces the alpha as far as possible while still producing the original color when alpha blending to the match color. Grim Reaper won't always produce the smallest possible alpha, and I'm pretty sure it won't always preserve the original color, since sometimes the adjusted RGB values will be clamped. When used with Erase Non-Matching Pixels, my plugin is similar to Color Cut, but much more flexible. I admit, if I'd realized that Hue/Saturation+ can erase background hues as well as it does, I wouldn't have written this plugin, which started out as Hue Eraser. Nevertheless, my plugin does have several useful additional features. First, it also allows the pixel's value to be considered; second, it has the Grim Reaperesque "partial erase"; third, it optionally allows the matching pixels to be kept; fourth, it allows choice of the primary and secondary colors as the matching color. The last may seem trivial, but it makes it easier to use the plugin with the color picker tool. Edited May 27, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
Cc4FuzzyHuggles Posted May 27, 2015 Share Posted May 27, 2015 (edited) My Hue/Saturation+ can erase colors by adjusting the alpha slider all the way to the left. That's so cool! Thanks for enlightening me of that function (I apparently had an outdated version of the plugin). However, MJW's plugin still seems nicer for removing colors since it has options and adjustments specifically made for removing color, and it has the ability to work with paint.net's primary and secondary colors, which for example, when using GrimColor or CutColor, is a SUPER handy feature. I wouldn't mind seeing a primary/secondary color option in hue/sat+, as that would help make re-coloring images easier too, but even if it did gain that feature, it still is mainly a color changing plugin in my opinion. But, I will be adding both plugins to my personal list of "good ways to cut out images/remove backgrounds". Edited May 27, 2015 by Cc4FuzzyHuggles Quote *~ Cc4FuzzyHuggles Gallery ~* Link to comment Share on other sites More sharing options...
MJW Posted May 28, 2015 Author Share Posted May 28, 2015 I think I've fixed most of the bugs. I also added an RGB distance tolerance, since sometimes that's useful, either alone or combined with the HSV tolerance. Quote Link to comment Share on other sites More sharing options...
Maximilian Posted May 29, 2015 Share Posted May 29, 2015 I haven't been able to compile it for my PdN 3.5.11 because it throws me an error that tells me that TransparentBlack is not defined in PaintDotNet.ColorBgra It happens in the function RemoveColor right where it reads return ColorBgra.TransparentBlack; I suppose it's due to the old version of Codelab, but since I'm not a coder I can't be sure. Quote Link to comment Share on other sites More sharing options...
BoltBait Posted May 29, 2015 Share Posted May 29, 2015 You could use: return ColorBgra.FromBgra(0,0,0,0);Same thing. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
MJW Posted May 29, 2015 Author Share Posted May 29, 2015 (edited) Maximilian, does it get an error if you change it to ColorBgra.Transparent? If not, I'll use that in the future, since all I really want to do is make the pixel transparent. BoltBait's solution will, of course, also work, but I'd prefer to use ColorBgra.Transparent if it works for older versions. Edited May 29, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
Maximilian Posted May 29, 2015 Share Posted May 29, 2015 Thank you both! However, ... Maximilian, does it get an error if you change it to ColorBgra.Transparent? It compiled correctly with this change, but now when I run the plugin I get the following error: File: C:\Archivos de programa\Paint.NET\Effects\HsvEraser.dll Name: HsvEraserEffect.HsvEraserEffectPlugin Version: 1.0.5627.35397 Author: MJW Copyright: Copyright © MJW Website: http://www.getpaint.net/redirect/plugins.html Full error message: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.Parameter name: defaultValue > maxValue at PaintDotNet.PropertySystem.ScalarProperty`1..ctor(Object name, T defaultValue, T minValue, T maxValue, Boolean readOnly, ValueValidationFailureResult vvfResult) in D:\src\pdn\pdn_3_5_11\src\Base\PropertySystem\ScalarProperty`1.cs:line 136 at PaintDotNet.PropertySystem.DoubleProperty..ctor(Object name, Double defaultValue, Double minValue, Double maxValue) in D:\src\pdn\pdn_3_5_11\src\Base\PropertySystem\DoubleProperty.cs:line 27 at HsvEraserEffect.HsvEraserEffectPlugin.OnCreatePropertyCollection() at PaintDotNet.Effects.PropertyBasedEffect.CreateConfigDialog() in D:\src\pdn\pdn_3_5_11\src\Effects\PropertyBasedEffect.cs:line 86 at PaintDotNet.Menus.EffectMenuBase.RunEffectImpl(Type effectType) in D:\src\pdn\pdn_3_5_11\src\PaintDotNet\Menus\EffectMenuBase.cs:line 799 Any ideas? Quote Link to comment Share on other sites More sharing options...
BoltBait Posted May 29, 2015 Share Posted May 29, 2015 Yeah, I have an idea... Upgrade to paint.net 4.0+ If you can't do that, try changing the line: double Amount7 = 0.15; // [0,1] Gray Upper Limit (S×V) to double Amount7 = 0.0; // [0,1] Gray Upper Limit (S×V) This is due to a bug in CodeLab or Paint.NET 3.5x (not sure which). Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
Maximilian Posted May 30, 2015 Share Posted May 30, 2015 Line changed = total success! Now I'll test the plugin! Quote Link to comment Share on other sites More sharing options...
Maximilian Posted May 31, 2015 Share Posted May 31, 2015 By the way, here's the 3.5.11-compatible version I compiled, in case somebody needs it HsvEraser for PdN 3.5.11.zip It's working great and I'm doing some interesting findings with it Quote Link to comment Share on other sites More sharing options...
Maximilian Posted June 2, 2015 Share Posted June 2, 2015 (edited) Back with a review! At times I do models on Sculptris to later on edit them for some PdN piece and the background gives me some trouble. I'm aware I have other choices to pick from, but Sculptris is lightweight and relatively easy to handle for someone with budding 3D-sculpting skills and an outdated computer, despite its several shortcomings. To name one, I can save a capture as a transparent png, which is not exactly the case because in fact the background is saved as black and what I do want is full transparency. So, my seemingly only chance is to save the capture with the program's interface's background included, which is a sort of dark gray to black gradient, and then see how I manage to remove it. In the following example I couldn't seem to adjust the magic wand's tolerance to a value that wouldn't mutilate parts of the creature, especially below the left armpit and above the left side of the head. The solution came from picking a color in the vicinity of the difficult area and playing with Value Tolerance and Gray Upper Limit, leaving all other settings at defaults. I'm glad I had this plugin and glad I discovered how to use it for this particular case Follows a side-to-side view of the non-transparent original capture and the result after removing the somewhat tricky gradient background: Edited September 30, 2018 by Maximilian fixed broken link Quote Link to comment Share on other sites More sharing options...
MJW Posted June 3, 2015 Author Share Posted June 3, 2015 Thank you very much for the review, Maximilian. That is quite a challenging image, since the background is so similar to the foreground. I gave it a try myself, and it was quite interesting. I fairly easily removed most of the background, but there remained ragged horizontal stripes. I was able to remove them a few at a time by using the color picker to select the color, then running the HSV Eraser. It sort of made me wish I'd made it an effect instead of an Adjustment, so that I could have used "Repeat HSV Eraser." I think a black background would be easier to eliminate, assuming no foreground edge pixels are black. If you can generate the same image against different backgrounds in Sculptris, you could use the difference of the images to eliminate the background. Quote Link to comment Share on other sites More sharing options...
Maximilian Posted June 3, 2015 Share Posted June 3, 2015 That is quite a challenging image, since the background is so similar to the foreground. I gave it a try myself, and it was quite interesting. I fairly easily removed most of the background, but there remained ragged horizontal stripes. I've seen better outcomes by applying the effect to specific selections, because at times the color one wants to get rid of may also show up in parts of the picture one needs to preserve, therefore rendering undesirable results. At least that's what I've experienced in this particular image on which I've done my tests. Of course it all depends on the specific characteristics of each piece. I was able to remove them a few at a time by using the color picker to select the color, then running the HSV Eraser. It sort of made me wish I'd made it an effect instead of an Adjustment, so that I could have used "Repeat HSV Eraser." It would be a very useful thing in matters of speeding up the workflow, as it may be necessary to repeat the operation in succession, especially when working on different selections like I suggested above. If you can generate the same image against different backgrounds in Sculptris, you could use the difference of the images to eliminate the background. Thanks a lot for this clue that should have occurred to me in the first place, but obviously didn't I tried it and it works wonders! The whole process would get faster with the aid of such generated mask if I had to process a good number of images. Gosh, one may have so much to learn yet! Quote Link to comment Share on other sites More sharing options...
MJW Posted June 3, 2015 Author Share Posted June 3, 2015 (edited) A method I find useful when cutting out backgrounds (which was mentioned by someone else recently) is to eliminate from consideration all but the edge of the foreground image by using the Paintbrush. The idea is the put a new semi-transparent layer on top, then paint over the foreground, almost up to the edge. It's pretty easy to do. It's a good idea to release the cursor button reasonably often so undoing a mistake doesn't undo everything up till then (though mistakes can also be fixed with the Eraser). Once the inside edge has been painted, the interior can be filled with the Paint Bucket. The unpainted area can then be selected and used as a mask to eliminate most of the foreground image. If you have a steady hand, well-defined smooth edges can often be painted well enough that no other form of background removal is necessary. I find it works much better than the Lasso tool. For hair, fur, and other rough edges like that, something like the HSV Eraser can be used to eliminate the background pixels near the edge. A nice feature of the painted mask is that it can be blurred, so the Magic Wand tolerance allows the mask to be expanded or contracted. EDIT: Something that just occurred to me, which I haven't tried but seems like a good idea, is to make a new layer that just contains the part of the image that was painted over. Then edit the original image with no selections except those to limit the background elimination to specific regions, not worrying too much about interior foreground pixels. Once the edge has been cleaned up, overlay the saved cutout interior, so that any lost interior pixels will be restored. ANOTHER EDIT: Or perhaps make the cutout-section layer visible, and behind the original image that will be edited. Then any erasures of non-edge foreground pixels won't even be visible during the edit. It will be as if only background and the edge foreground pixels can be edited. Perhaps the mask could even be expanded with a blur to generate a selection that's outside the foreground image, which could then be used to eliminate all but the edge background pixels. I'm not sure if that would make it easier or harder to remove the background. Edited June 3, 2015 by MJW 1 Quote Link to comment Share on other sites More sharing options...
Maximilian Posted June 4, 2015 Share Posted June 4, 2015 These are really neat ideas I'll try out soon. I'll have to take a good note of them all. Thanks for taking the time to write all that! The difference mask and/or this plugin and the magic wand have proved good enough for what I'm working on at the moment, but then there's the tricky matter of hair that always causes trouble. At one time I tried some of that and the results were unsatisfactory, like I lost threads of hair in the resulting picture, therefore losing the original's realism. Then again, I didn't have this plugin back then, for which reason I'm interested in giving the matter another try. Quote Link to comment Share on other sites More sharing options...
MJW Posted June 4, 2015 Author Share Posted June 4, 2015 Yesterday, just for the heck of it, I tried removing the background from a picture of Humphrey Bogart posted on a thread about cutting out backgrounds. I'd forgotten how useful the Erase tool can be when the edge is smooth. Painting a mask layer is better for more complex situations, but for simple edges, just erasing the background is quick and quite easy. Generally, it works best to use a reasonably large brush size. The HSV Eraser was mostly written to handle tricky situations like hair and fur. Those are difficult because the background and foreground are mixed together, so many of the pixels are half background and half foreground. If the colors are similar, then those pixels can usually be left unchanged and later feathered. If the colors contrast, then hopefully the HSV Eraser's partial-erase feature can be used to eliminate the background color while leaving the foreground color. (Of course, if you can generate different backgrounds for the same image, that makes things a lot simpler, and is far better than erasing or painting a mask.) Quote Link to comment Share on other sites More sharing options...
Maximilian Posted June 8, 2015 Share Posted June 8, 2015 The peculiar features of my eyes make me choose dark colors for most things and when I do the captures on Sculptris I have the dark backgrounds on one hand and a dark main object on the other, which at times makes things harder when I have to create the difference mask because both the mask and the background appear dark at first sight. What I've been doing lately is find a way to highlight the main object while preserving the darkness of the backgrounds, for example by doing a preliminary Additive blending before doing the Difference thing. This way, the resulting mask looks more visible, or so I feel it. Perhaps all this is way too obvious, but anyway I thought I'd say it. Sometimes one gets overexcited to achieve a final result and may overlook basic procedures that might eventually improve such result Quote Link to comment Share on other sites More sharing options...
MJW Posted June 8, 2015 Author Share Posted June 8, 2015 I think it would be quite easy to write a little plugin that would erase the matching or non-matcing colors for two images, if that would be useful. Quote Link to comment Share on other sites More sharing options...
Maximilian Posted June 8, 2015 Share Posted June 8, 2015 Like I always say, one can always put a good plugin to good use! Quote Link to comment Share on other sites More sharing options...
MJW Posted June 10, 2015 Author Share Posted June 10, 2015 (edited) If you post an example of the same image with different backgrounds, I'll see what I can do. Edited June 10, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
Maximilian Posted June 11, 2015 Share Posted June 11, 2015 This is a random sculpture on a black background, and the same random sculpture on a dark gray gradient background. However, it seems I have found yet another workaround. Yesterday, Red ochre made me notice the possibility to change the Sculptris interface background to an image of one's choice, which of course I should have noticed by myself but was too silly for such a simple find Anyway, I made a light blue image and set it as the interface background, which appears to contrast nicely with the mostly darkish materials I use when sculpting. This should really simplify the process of cutting backgrounds. It would nonetheless be interesting to see such a plugin as you suggest. I suppose it may be helpful for other situations, but only if you have time to put on it. No hurries really Quote Link to comment Share on other sites More sharing options...
MJW Posted June 13, 2015 Author Share Posted June 13, 2015 (edited) Here's the source for a little plugin to erase the mismatches between two images: Hidden Content: // Author: MJW // Name: Mismatch Eraser // Title: Mismatch Eraser // Submenu: color // Desc: Erase mismatched pixels between clipboard and image // Keywords: erase mismatch clipboard #region UICode #endregion // Here is the main render loop function void Render(Surface dst, Surface src, Rectangle rect) { bool haveCbImage = (img != null) && (src.Width == img.Width) && (src.Height == img.Height); for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { ColorBgra CbPixel; ColorBgra CurrentPixel = src[x, y]; if (IsCancelRequested) return; // If clipboard has an image, get it. Check every time. if (haveCbImage) haveCbImage = (img != null); CbPixel = haveCbImage ? img[x, y] : CurrentPixel; dst[x, y] = (CurrentPixel == CbPixel) ? CurrentPixel : ColorBgra.Transparent; } } } // Setup for getting an image from the clipboard protected Surface img { get { if (_img != null) return _img; else { System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(GetImageFromClipboard)); t.SetApartmentState(System.Threading.ApartmentState.STA); t.Start(); t.Join(); return _img; } } } private Surface _img = null; private void GetImageFromClipboard() { Bitmap aimg = null; System.Windows.Forms.IDataObject clippy; try { clippy = System.Windows.Forms.Clipboard.GetDataObject(); if (clippy != null) { if (System.Windows.Forms.Clipboard.ContainsData("PNG")) { // Handle bitmaps with transparency Object png_object = System.Windows.Forms.Clipboard.GetData("PNG"); if (png_object is System.IO.MemoryStream) { System.IO.MemoryStream png_stream = png_object as System.IO.MemoryStream; aimg = (Bitmap)Image.FromStream(png_stream); } } else if (clippy.GetDataPresent(System.Windows.Forms.DataFormats.Bitmap)) { // If that didn't work, try bitmaps without transparency aimg = (Bitmap)clippy.GetData(typeof(System.Drawing.Bitmap)); } } } catch (Exception) { } if (aimg != null) { _img = Surface.CopyFromBitmap(aimg); } else { _img = null; } } Here's a zip file of the effect: MismatchEraser.zip Here's an icon (yes, I actually made one for this effect): The plugin is in the Effects>Color menu. Load one image into PDN, and copy the other into the clipboard. The images have to be the same size. The plugin isn't fancy. If the pixel doesn't match, it just erases it, with no attempt at antialiasing. Edited June 13, 2015 by MJW 1 Quote Link to comment Share on other sites More sharing options...
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.