What's the point for the GameBoy of having multiple color palettes? - emulation

Each pixel is composed by two bits, allowing up to 4 shades of gray. From the LCD Monochrome Palettes section of the pandocs we can develop the algorithm for getting the color (in the case I've understood it correctly):
COLOR_NUMBER_PALETTE_BITS = {
0: (1, 0),
1: (3, 2),
2: (5, 4),
3: (7, 6)
}
COLORS = {0: WHITE, 1: LIGHT_GRAY, 2: DARK_GRAY, 3: BLACK}
def get_pixel_color(palette_address, color_number):
palette = read_memory(palette_address)
high_bit, low_bit = COLOR_NUMBER_PALETTE_BITS[color_number]
color_high_bit = get_bit(palette, high_bit)
color_low_bit = get_bit(palette, low_bit)
color = (color_high_bit << 1) | color_low_bit
return COLORS[color]
But just looking at the function signature we can deduce that same color numbers may result in different colors; it depends on the palette we're using.
My question is, why do we need multiple color palettes when two of them are identical, and the only difference with the third one is that 0 is transparent instead of white? Why do the palette definition change, instead of the color number used to get the color from the palette?

What do you mean "two of them are identical"? You have three different color palettes. One for background and window. Two for sprites which you can select for each sprite individually using special bit in sprite attributes. Why changing palette instead of color numbers? It's much cheaper to change color palette or sprite attributes than to rewrite each tile of a sprite or window to achieve some effect on the screen. You can even change palettes in realtime as the Gameboy draws the image on the screen.
For example, let's say I wanted to implement flashing effect where whole background flashes between normal colors and white or black. Instead of rewriting every background tile on every frame I could just change the palette and time it exactly to only affect parts of the screen I need. There's even an article describing similar technique.

Related

Reduce components included by otsu threshold python opencv

I am trying to segment the blue components from a set of images. In most images where blue components have a large spread, otsu thresholded image works properly well. However, for images where blue components are minimal, the results are not ok and seems to include the non-relevant sections. Example below:
Are there ways to improve the otsu thresholding such that only relevant parts are segmented but not necessarily making the other images suffer?
I already tried global and adaptive thresholding but otsu particularly captured betters which however included unnecessary details.
Here's the code:
l_image = remove_background(image)
l_image = cv2.cvtColor(l_image, cv2.COLOR_BGR2GRAY)
ret1,th1 = cv2.threshold(l_image,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
mask = (th1 != 255)
sel = np.ones_like(image)
sel[mask] = image[mask]
sel = cv2.cvtColor(sel, cv2.COLOR_HSV2BGR)
#we simply set these channels to 0 to remove excess background
sel[:,:,1] = 0
sel[:,:,2] = 0
Here's the sample image.
The main issue with the logic in your code is that you are looking for something that is distinguished primarily by color, but throw away the color information first by converting the image to grayscale.
Instead, consider looking at color properties of each pixel. One easy way to do so is to look at the HCV color space. This is a similar color space to the more common HSV, with "C" for chroma instead of "S" for saturation, where S = C / V. I'm suggesting this because it's so easy to compute the "C" channel, which is the one that would have most of the contrast in this image. Note that all the complexity is in computing "H", the hue, and that would be ideally used to find a specific color independently of its brightness, but that requires a double threshold on the "H" channel plus a threshold on the "S" channel. For this simple case, a single threshold on the "S" channel is sufficient to find the colored regions: we have only blue, we don't care about what color it is, we just want to find the color.
To compute the "C" (chroma) channel, we find the difference between the largest and the smallest of the RGB values (for each pixel independently):
rgbmax = np.amax(image, axis=2)
rgbmin = np.amin(image, axis=2)
c = rgbmax - rgbmin
As you can guess, a simple threshold of this image leads to finding the colored regions. The green background can easily be subtracted before processing, or after.
Edit: after #Cris Luengo comment, the green channel works better than the blue one.
You can apply Otsu's threshold on the green channel (of BGR).
Results are not perfect but much better.
img = img[:,:,1] #get the green channel
th, img = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)
output:

How to tell if a color is imaginary/impossible?

Short version
How can I tell if a color (e.g. XYZ) is impossible? (Wikipedia: Imposible color)
For example, this color is impossible:
XYZ: (15.96, 84.04, 0)
xyY: (0.1595, 0.8404, 0.8404)
Lab: (93, -196, 161) (D65 whitepoint)
It's impossible because it lies outside of the chromacity diagram:
How can I know that?
Incorrect code
The goal is for someone to fill in the function:
Boolean IsImaginaryColor(Single X, Single Y, Single Z)
{
//...TODO: Get someone to answer the question.
}
Right now we know that if any of the components of a corresponding LMS color are negative, then the color is imaginary.
That is a necessary, but not sufficient, condition for a color to be real. You can have all three components of LMS be positive, but it still be an imaginary color.
Boolean IsImaginaryColor(Single X, Single Y, Single Z)
{
//If any component of LMS color is negative,
//then the color is definitely imaginary.
LMSColor lms = XYZtoLMS(X, Y, Z);
if ((lms.L < 0) or (lms.M < 0) or (lms.S < 0))
return true;
//The color may still be imaginary,
//but i don't know how to solve that problem
//So as a first approximation i'll say it's real
return false;
}
LMSColor XYZtoLMS(Single X, Single Y, Single Z)
{
//perform Matrix multiplication:
//
// LMS = M * XYZ
//
// Where M is the M_CAT02 transformation matrix from CIECAM02
//
// 0.7328, 0.4296, -0.1624
// -0.7036, 1.6975, 0.0061
// 0.0030, 0.0136, 0.9834
LMSColor result;
result.L = 0.7328*X + 0.4296*Y + -0.1624*Z
result.M = -0.7036*X + 1.6975*Y + 0.0061*Z
result.S = 0.0030*X + 0.0136*Y + 0.9834*Z
}
In the xy color plane, this gives a good first-approximation (and nice visual indication) of impossible colors:
But the calculation still gives colors outside the chromacity diagram *(technically they're outside the "spectral locus"). So obviously only checking for negative components in LMS is incomplete.
Long Version
I am rendering a color picker. For example:
to pick an Lab color
you pick an ab color
for a given L plane
This is similar to what you can already do in Photoshop:
So in this case I've picked the color:
Lab: (72, -58, 119)
That color (assuming the D65 whitepoint) corresponds to the XYZ color:
Lab: (72, -58, 119)
XYZ: (25.22, 43.66, 0.36)
You can tell if a real color is outside the sRGB color gamut if one of its components is either:
less than 0
greater than 255
This XYZ color lies outside of the sRGB color space because one of it's components is negative:
XYZ: (25.22, 43.66, 0.36)
Lab: (72, -58, 119) (D65)
RGB: (106.1, 199.6, -234.7) (sRGB)
Photoshop already knows if a color is outside the sRGB color gamut, and will display a gumut warning:
But I'd like to go one step further
I can already know if a color is outside the sRGB color gamut.
But now i want to know if a color is imaginary, so i can continue to show the gamut, but hide completely impossible colors. A conceptual mockup might be:
Warning: I have no idea which of those colors actually are impossible. This is only the idea of the concept.
So what I need to know is if a color is impossible.
Background Theory - What is an example of an impossible color?
The Wikipedia page on Impossible colors notes that while the primaries for the sRGB color space all lie inside the spectral locus - and so are all real colors:
The ProPhotoRGB color space does use some primaries that are impossible:
The ProPhoto RGB color space uses imaginary green and blue primaries to obtain a larger gamut (space inside the triangle) than would be possible with three real primaries. However, some real colors are still irreproducible.
So now I have a concrete example of an impossible color: the green primary of the ProPhoto RGB color space:
| Color | CIE x | CIE y |
|-------|--------|--------|
| red | 0.7347 | 0.2653 |
| green | 0.1596 | 0.8404 | <--- this one
| blue | 0.0366 | 0.0001 |
| white | 0.3457 | 0.3585 |
This impossible color, given different color spaces, is:
xyY: (0.1596, 0.8404, 0.8404)
XYZ: (15.96, 84.04, 0)
LMS: (47.80, 131.43, 1.19)
Lab: (93.4679, -195.9973, 161.1515)
LCHab: (93.4679, 253.7415, 140.5725)
How can I tell that this color is impossible?
Given an XYZ color, how can I tell that it is impossible? E.g.:
XYZ: 15.96, 84.04, 0
Bonus Chatter
It's important to note the difference between
colors existing outside some gamut
and imaginary colors
A quick single-image primer would be:
Gamut: a color may not be displayable on your monitor, or printer, or phone, but it is still a real color - you could get a combination of Electromagnetic Waves of various wavelengths and intensities to generate the color
Imaginary: No combination of EM waves, of any intensities, of any wavelengths, can generate that response in the Long, Medium, and Short human cones
I already know how to tell if a color exists outside a particular color gamut.
I want to know if a color also exists outside the spectral locus.
In other words: i want to know if it is imaginary.
Bruce Lindbloom has a nice graphic that raises the issues of colors outside the Lab color space when you arbitrary choose to arbitrarily limit the a and b component values to +- 128:
Bonus Reading
https://physics.stackexchange.com/q/94375/
Determine that a Luv Color is non-imaginary
https://physics.stackexchange.com/questions/420614
This is a duplicate of the answer I gave here: Determine that a Luv Color is non-imaginary which relate to https://stackoverflow.com/a/48396021/931625
I think the safe way is to compute the XYZ volume boundaries and check if you are within or outside.

networkx: set different alpha for each node?

I want to set a different alpha for each node. It's easy to set a different color for each node but alpha only excepts a single value. Anyone know how to do this?
(My goal is to have a color gradient from blue to red. If the value is below the midpoint it's blue and if above it's red. Alpha would set the gradient.)
nx.draw_networkx_nodes(g,pos=pos,nodelist=nodelist,
node_color=node_color, alpha=1.0)
The alpha value will control transparency, not color.
If you are already supplying the node_color parameter, your nodes will be colored.
If you want them to go from blue to red based on those intensities, instead of alpha, use a colormap. E.g. seismic colormap goes from red to blue.
nx.draw_networkx_nodes(g, pos=pos, nodelist=nodelist, node_color=node_color, cmp='seismic')
EDIT:
I stumbled across some odd behavior trying to dig deeper into this.
I would have thought that networkx's plotting would behave like matplotlib's scatter plot, and accept rgba colors, allowing you to specify particular colors and transparency. But when I call draw_networkx_nodes with an array of 4-tuples to denote rgba colors, it sets all alpha values to 1.
rgba_colors = np.zeros((5,4))
rgba_colors[:,0] = np.linspace(1,0,5) #red
rgba_colors[:,2] = np.linspace(0,1,5) #blue
rgba_colors[:,3] = np.linspace(0.1,1,5) #alpha values
plt.scatter([1,2,3,4,5],[1,2,3,4,5], color=rgba_colors)
This plots some points with varying color and transparency. But, if you try plotting with networkx, not only does the resulting plot have no transparency, the variable rgba_colors has actually been modified.
G = nx.complete_graph(5)
pos = {0: [0,0], 1: [1,1], 2: [2,2], 3: [2,1], 4: [2,3]}
nx.draw_networkx_nodes(G, pos=pos, node_color=rgba_colors)
print(rgba_colors)
I'm not sure why this is happening.

Built in colormaps in Matlab

I want a lighter version of the "cyan" color, using the function colormap('cyan'). How do you do this?
Check out the function BRIGHTEN:
X = spiral(8);
image(X)
colormap(winter), colorbar
brighten(0.6)
Another trick is to right click on the colorbar and select Interactive Colormap Shift, this allows to shift the color-to-data mapping using mouse dragging.
Pure cyan is represented by the RGB triple [0 1 1]. To make it lighter, just increase the red component (ex: [0.5 1 1]), thus moving it closer to pure white ([1 1 1]). If you want to make a colormap that spans from pure cyan through lighter shades of cyan all the way to pure white, you can do the following:
nValues = 128; %# The number of unique values in the colormap
map = [linspace(0,1,nValues)' ones(nValues,2)]; %'# 128-by-3 colormap
Now you can set the colormap to the one made above using the COLORMAP function:
colormap(map);
For more discussion of colors in MATLAB, check out this link.
For me colormap('cyan') fails because cyan is undefined.
However, you can create your own colors easily. If cyan is equivalent to [0,1,1] a lighter color would be [0,1,1] + [.1,0,0] = [.1,1,1] or rather just increase the R in RGB to increase the luminosity.

How do I set a surf to one color (no gradient) in my matlab-plot?

My dataset consists of three vectors (x,y and z). I plot these values as dots in a 3d-plot with plot3(x,y,z), which is fine. I also want to show a plane in the same plot. To get the data of this plot I use linear regression on x and y to get a new z.
This is how it looks:
(source: bildr.no)
I want the surf to be filled with only one color (say light blue or gray) and set the opacity, to make it see-through. How can I do this?
The easiest way to create a surface that has just 1 color and a given transparency value is to set the 'FaceColor' and 'FaceAlpha' properties of the surface object:
hSurface = surf(...your arguments to create the surface object...);
set(hSurface,'FaceColor',[1 0 0],'FaceAlpha',0.5);
This example sets the surface color to be red and the transparency to 0.5. You can also set the edge properties too (with 'EdgeColor' and 'EdgeAlpha').
It is not clear to me what you want to do. When you say one color for the surf, do you mean exactly one color, or do you mean you want shades of gray?
Here is some code that will do a variety of things, you can choose which lines to use:
x = rand(1,20);
y = rand(1,20);
z = rand(1,20);
[X,Y] = meshgrid(linspace(0,1,10),linspace(0,1,10));
Z = rand(10)*0.1;
clf
plot3(x,y,z,'.');
hold on
h = surf(X,Y,Z)
hold off
%% This will change the color
colormap(copper)
%% This will remove colordata
set(h, 'cdata',zeros(10))
%% This will make transparent
alpha(0.5)
Completing the answer from gnovice, an extra ingredient in set(hsurface...) may be required (Matlab R2010b 64):
hSurface = surf(...your arguments to create the surface object...);
set(hSurface, 'FaceColor',[1 0 0], 'FaceAlpha',0.5, 'EdgeAlpha', 0);
to make invisible the point-to-point edges of the plotted surface
#matlabDoug has what you need, I think. The property cdata holds color data that gets a color map applied to it. Setting it to an array the same size as your surface data, with each element in that array having the same value, will make your surface one color. With the default color map, setting everything in cdata to zero will make your surface blue, and setting everything to 1 will make the surface red. Then you can play with the alpha to make it transparent.

Resources