How to make Texture unblurred?

This post is related to this post, But somewhat different. Since Wizard focus on alpha channel, and didn't got an answer. So I made this post.

My system is Windows 10, and Mathematica 11.2

If I run

plot = Image[RandomReal[1., {6, 6}]]


I got

Then I texture this image on a square like this

Graphics[{Texture[plot], EdgeForm[],
Append[Polygon @@ RegionBoundary[Rectangle[]],
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}]


I got

You can see it is already blurred

What is worse, if we generate a color image

plot = Image[RandomReal[1., {6, 6, 3}]]


and texture it.

Graphics[{Texture[plot], EdgeForm[],
Append[Polygon @@ RegionBoundary[Rectangle[]],
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}]


I got

Which is a total mess.

The difference between my result and Wizard's result is that, even I don't set alpha channel, I already screw up the color image texture.

So why Texture always blur image? I check the doc, it seems that this blurring feature is not mentioned. Is it possible to make Texture clear especially for color image generated by Image?

update

Thanks to J.M. and kglr. They both suggest that it is a problem of low-res of image. But I have a counter example, which suggest that there is some subtle effect. Take a look at this, using ArrayPlot

plot = ArrayPlot[RandomReal[1., {6, 6}], ColorFunction -> "Rainbow",
Frame -> None]


then texture it with the same method,

Graphics[{Texture[plot], EdgeForm[],
Append[Polygon @@ RegionBoundary[Rectangle[]],
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}]


you will got

You will notice there is still some blur, but much weaker. And the color is much much better than Image texture, but seems not as vivid as original plot.

If you test ImageDimensions@plot. Both ArrayPlot and Image generate 6x6 image. So at least, this example shows low-res may not be a real reason for poor texture of Image

• try plot = Image[RandomReal[1., {6, 6}], ImageSize -> 500]?
– kglr
Mar 14, 2018 at 2:54
• This seems to be a problem when your images are low-res. At least for this simple case, try plotNew = ImageResize[plot, Scaled[50], Resampling -> "Nearest"]; Graphics[{Texture[plotNew], EdgeForm[], Polygon[{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}] Mar 14, 2018 at 2:54
• Rasterize[plot ,RasterSize ->500, ImageResolution -> 300 ] also works in both v9 an v11.
– kglr
Mar 14, 2018 at 3:12
• Point 7 under "More Details" of the docs for Texture[]: "Texture[obj] is equivalent to Texture[Rasterize[obj]] and will rasterize obj at the size and resolution it would normally be displayed in a notebook." With that, try plot = Rasterize[ArrayPlot[RandomReal[1., {6, 6}], ColorFunction -> "Rainbow", Frame -> None]]; ImageDimensions[plot]. Mar 14, 2018 at 4:48
• The problem is one of texture filtering (scroll down to the "Texture Filtering" section on that page). Most graphics APIs allow one to choose between nearest neighbour (which is what you want) and bilinear filtering (which is what Mathematica does), but it seems Mathematica doesn't give you that choice. So you'll have to work around it, either by creating a high-resolution texture, or by creating lots of little squares and colouring them individually.
– user484
Mar 14, 2018 at 6:35

Rahul is correct in his comment. To map a texture to an object, you use VertexTextureCoordinates to specify where the texture is glued to the object. The problem is, that those few points are not enough because you need a color for every single position inside your polygon.

When you know the coordinates of your polygon that are mapped to the texture corners, you can map each point inside the polygon to point of the texture. These calculated points will almost never lie on a perfect pixel and you will not have exactly as many points as you have image pixels.

The question is, how do you calculate the color at pixel position (2.34, 4.003)? You interpolate the pixels of your texture. As Rahul pointed out, bilinear interpolation is used. When we know this, we can recreate the artifact ourselves. Just take your image and create a larger one with linear resampling:

plot = Image[RandomReal[1., {6, 6, 3}]];
ImageResize[plot, 128, Resampling -> "Linear"]


Since it seems we cannot set (I haven't looked carefully!) the interpolation aka "Texture Filtering" in Mathematica, one choice is to create a larger image by resampling linearly yourself and use a larger texture image:

plot = Image[RandomReal[1., {6, 6, 3}]];
tex = ImageResize[plot, 256, Resampling -> "Constant"];

Graphics[{Texture[tex], EdgeForm[],
Polygon[{{0, 0}, {1, 0}, {1, 1}, {0, 1}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]
}]


This is not perfect, but way better.

• Thank you so much, halirutan. Very clear : ) Mar 14, 2018 at 13:15

There is a Method option for Graphics(3D) to set the texture sampling to constant (nearest):

Graphics[{Texture[tex], EdgeForm[],
Polygon[{{0, 0}, {1, 0}, {1, 1}, {0, 1}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]},
Method -> {"TextureSampling" -> "Nearest"}]


It does well for up-scaling in the middle, but there are artifacts around the outer edge due to the repeating nature of textures. This edge-artifact is more noticeable if the texture is used in Graphics and less noticeable (to me) in Graphics3D.